PluginProbe
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor / 2.0.8
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor v2.0.8
2.0.13 2.0.12 2.0.11 2.0.10 2.0.9 trunk 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8
blockenberg / blocks / github-card / frontend.js

frontend.js in Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor 2.0.8, at blocks/github-card/frontend.js

320 lines 14.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 (function () {
2 'use strict';
3
4 // Language color map for GitHub
5 var LANG_COLORS = {
6 'JavaScript': '#f1e05a', 'TypeScript': '#3178c6', 'Python': '#3572A5',
7 'PHP': '#4F5D95', 'Ruby': '#701516', 'Go': '#00ADD8', 'Rust': '#dea584',
8 'CSS': '#563d7c', 'HTML': '#e34c26', 'C': '#555555', 'C++': '#f34b7d',
9 'Java': '#b07219', 'Swift': '#F05138', 'Kotlin': '#A97BFF', 'Dart': '#00B4AB',
10 'Shell': '#89e051', 'Vue': '#41b883', 'Svelte': '#ff3e00'
11 };
12
13 function formatNumber(n) {
14 if (!n && n !== 0) return '';
15 if (n >= 1000000) return (n / 1000000).toFixed(1) + 'M';
16 if (n >= 1000) return (n / 1000).toFixed(1) + 'k';
17 return n.toString();
18 }
19
20 function formatDate(iso) {
21 if (!iso) return '';
22 var d = new Date(iso);
23 var now = new Date();
24 var diff = Math.floor((now - d) / 1000);
25 if (diff < 60) return 'Updated just now';
26 if (diff < 3600) return 'Updated ' + Math.floor(diff / 60) + 'm ago';
27 if (diff < 86400) return 'Updated ' + Math.floor(diff / 3600) + 'h ago';
28 if (diff < 2592000) return 'Updated ' + Math.floor(diff / 86400) + 'd ago';
29 return 'Updated ' + d.toLocaleDateString(undefined, { month: 'short', day: 'numeric', year: 'numeric' });
30 }
31
32 function getCached(key, maxAge) {
33 try {
34 var raw = localStorage.getItem(key);
35 if (!raw) return null;
36 var obj = JSON.parse(raw);
37 if (Date.now() - obj.ts > maxAge * 60 * 1000) return null;
38 return obj.data;
39 } catch (e) { return null; }
40 }
41
42 function setCache(key, data) {
43 try { localStorage.setItem(key, JSON.stringify({ ts: Date.now(), data: data })); } catch (e) { }
44 }
45
46 function typoCssVarsForEl(typo, prefix, el) {
47 if (!typo || typeof typo !== 'object') return;
48 var map = {
49 family: 'font-family', weight: 'font-weight', style: 'font-style',
50 decoration: 'text-decoration', transform: 'text-transform',
51 sizeDesktop: 'font-size-d', sizeTablet: 'font-size-t', sizeMobile: 'font-size-m',
52 lineHeightDesktop: 'line-height-d', lineHeightTablet: 'line-height-t', lineHeightMobile: 'line-height-m',
53 letterSpacingDesktop: 'letter-spacing-d', letterSpacingTablet: 'letter-spacing-t', letterSpacingMobile: 'letter-spacing-m',
54 wordSpacingDesktop: 'word-spacing-d', wordSpacingTablet: 'word-spacing-t', wordSpacingMobile: 'word-spacing-m'
55 };
56 Object.keys(map).forEach(function (k) {
57 if (typo[k] !== undefined && typo[k] !== '') {
58 var v = typo[k];
59 if (['sizeDesktop','sizeTablet','sizeMobile'].indexOf(k) !== -1) {
60 v = v + (typo.sizeUnit || 'px');
61 } else if (['lineHeightDesktop','lineHeightTablet','lineHeightMobile'].indexOf(k) !== -1) {
62 v = v + (typo.lineHeightUnit || '');
63 } else if (['letterSpacingDesktop','letterSpacingTablet','letterSpacingMobile'].indexOf(k) !== -1) {
64 v = v + (typo.letterSpacingUnit || 'px');
65 } else if (['wordSpacingDesktop','wordSpacingTablet','wordSpacingMobile'].indexOf(k) !== -1) {
66 v = v + (typo.wordSpacingUnit || 'px');
67 }
68 el.style.setProperty(prefix + map[k], String(v));
69 }
70 });
71 }
72
73 document.querySelectorAll('.bkbg-ghc-app').forEach(function (app) {
74 var opts = {};
75 try { opts = JSON.parse(app.dataset.opts || '{}'); } catch (e) { }
76
77 var mode = opts.mode || 'repo';
78 var username = opts.username || '';
79 var repoName = opts.repoName || '';
80 var showAvatar = opts.showAvatar !== false;
81 var showBio = opts.showBio !== false;
82 var showStats = opts.showStats !== false;
83 var showLanguage = opts.showLanguage !== false;
84 var showTopics = opts.showTopics !== false;
85 var showLastUpdate = opts.showLastUpdate !== false;
86 var openInNewTab = opts.openInNewTab !== false;
87 var cacheMinutes = opts.cacheMinutes || 60;
88 var cardRadius = opts.cardRadius || 16;
89 var padding = opts.padding || 24;
90 var avatarSize = opts.avatarSize || 64;
91 var align2 = opts.align2 || 'center';
92 var maxWidth = opts.maxWidth || 480;
93 var cardBg = opts.cardBg || '#0d1117';
94 var headingColor = opts.headingColor || '#e6edf3';
95 var descColor = opts.descColor || '#8b949e';
96 var metaColor = opts.metaColor || '#8b949e';
97 var statBg = opts.statBg || '#161b22';
98 var linkColor = opts.linkColor || '#58a6ff';
99 var borderColor = opts.borderColor || '#30363d';
100 var sectionBg = opts.sectionBg || '';
101
102 if (!username) { app.style.display = 'none'; return; }
103 if (sectionBg) app.style.background = sectionBg;
104
105 typoCssVarsForEl(opts.typoHeading, '--bkbg-ghc-hd-', app);
106 typoCssVarsForEl(opts.typoBody, '--bkbg-ghc-bd-', app);
107 typoCssVarsForEl(opts.typoMeta, '--bkbg-ghc-mt-', app);
108
109 // Alignment wrapper
110 app.style.textAlign = align2;
111
112 // Loading state
113 var loading = document.createElement('div');
114 loading.className = 'bkbg-ghc-loading';
115 loading.style.cssText = 'background:' + cardBg + ';border:1px solid ' + borderColor + ';border-radius:' + cardRadius + 'px;max-width:' + maxWidth + 'px;margin:' + (align2 === 'center' ? '0 auto' : align2 === 'right' ? '0 0 0 auto' : '0') + ';color:' + metaColor + ';';
116 var spinner = document.createElement('div');
117 spinner.className = 'bkbg-ghc-spinner';
118 loading.appendChild(spinner);
119 loading.appendChild(document.createTextNode('Loading GitHub data…'));
120 app.appendChild(loading);
121
122 // API URL
123 var apiUrl = mode === 'repo' && repoName
124 ? 'https://api.github.com/repos/' + username + '/' + repoName
125 : 'https://api.github.com/users/' + username;
126
127 var cacheKey = 'bkbg_ghc_' + apiUrl;
128 var cached = getCached(cacheKey, cacheMinutes);
129
130 function renderCard(data) {
131 app.removeChild(loading);
132
133 var marginStyle = align2 === 'center' ? '0 auto' : align2 === 'right' ? '0 0 0 auto' : '0';
134 var ghUrl = data.html_url || ('https://github.com/' + username);
135
136 var card = document.createElement('a');
137 card.className = 'bkbg-ghc-card';
138 card.href = ghUrl;
139 card.target = openInNewTab ? '_blank' : '_self';
140 card.rel = 'noopener noreferrer';
141 card.style.cssText = 'background:' + cardBg + ';border:1px solid ' + borderColor + ';border-radius:' + cardRadius + 'px;padding:' + padding + 'px;max-width:' + maxWidth + 'px;margin:' + marginStyle + ';display:block;color:inherit;text-decoration:none;';
142
143 // Header
144 var header = document.createElement('div');
145 header.className = 'bkbg-ghc-header';
146
147 if (showAvatar && data.owner && data.owner.avatar_url) {
148 var img = document.createElement('img');
149 img.className = 'bkbg-ghc-avatar';
150 img.src = data.owner.avatar_url;
151 img.alt = data.owner.login;
152 img.width = avatarSize;
153 img.height = avatarSize;
154 img.style.cssText = 'width:' + avatarSize + 'px;height:' + avatarSize + 'px;border-radius:' + (mode === 'repo' ? '8px' : '50%') + ';object-fit:cover;';
155 header.appendChild(img);
156 } else if (showAvatar && data.avatar_url) {
157 var img2 = document.createElement('img');
158 img2.className = 'bkbg-ghc-avatar';
159 img2.src = data.avatar_url;
160 img2.alt = data.login;
161 img2.width = avatarSize;
162 img2.height = avatarSize;
163 img2.style.cssText = 'width:' + avatarSize + 'px;height:' + avatarSize + 'px;border-radius:50%;object-fit:cover;';
164 header.appendChild(img2);
165 }
166
167 var nameCol = document.createElement('div');
168 var nameRow = document.createElement('div');
169 nameRow.className = 'bkbg-ghc-name-row';
170 var nameLink = document.createElement('a');
171 nameLink.href = ghUrl;
172 nameLink.target = openInNewTab ? '_blank' : '_self';
173 nameLink.rel = 'noopener noreferrer';
174 nameLink.textContent = mode === 'repo' ? (data.full_name || username + '/' + repoName) : (data.name || data.login || username);
175 nameLink.style.color = linkColor;
176 nameRow.appendChild(nameLink);
177
178 var handleDiv = document.createElement('div');
179 handleDiv.className = 'bkbg-ghc-handle';
180 handleDiv.style.color = metaColor;
181 handleDiv.textContent = mode === 'repo' ? (data.language ? data.language : '') : ('@' + (data.login || username));
182 nameCol.appendChild(nameRow);
183 if (handleDiv.textContent) nameCol.appendChild(handleDiv);
184 header.appendChild(nameCol);
185 card.appendChild(header);
186
187 // Bio / Description
188 if (showBio) {
189 var descText = mode === 'repo' ? data.description : data.bio;
190 if (descText) {
191 var desc = document.createElement('div');
192 desc.className = 'bkbg-ghc-desc';
193 desc.style.color = descColor;
194 desc.textContent = descText;
195 card.appendChild(desc);
196 }
197 }
198
199 // Repo meta row (language + topics)
200 if (mode === 'repo') {
201 var metaRow = document.createElement('div');
202 metaRow.className = 'bkbg-ghc-meta-row';
203 metaRow.style.color = metaColor;
204
205 if (showLanguage && data.language) {
206 var langSpan = document.createElement('span');
207 langSpan.className = 'bkbg-ghc-lang';
208 var dot = document.createElement('span');
209 dot.className = 'bkbg-ghc-lang-dot';
210 dot.setAttribute('data-lang', data.language);
211 dot.style.background = LANG_COLORS[data.language] || '#8b949e';
212 langSpan.appendChild(dot);
213 langSpan.appendChild(document.createTextNode(data.language));
214 metaRow.appendChild(langSpan);
215 }
216
217 if (showTopics && data.topics && data.topics.length) {
218 data.topics.slice(0, 5).forEach(function (topic) {
219 var t = document.createElement('a');
220 t.className = 'bkbg-ghc-topic';
221 t.href = 'https://github.com/topics/' + topic;
222 t.target = '_blank';
223 t.rel = 'noopener noreferrer';
224 t.textContent = topic;
225 t.style.cssText = 'background:rgba(56,139,253,0.15);color:' + linkColor + ';';
226 metaRow.appendChild(t);
227 });
228 }
229
230 if (metaRow.children.length) card.appendChild(metaRow);
231 }
232
233 // Stats
234 if (showStats) {
235 var statsRow = document.createElement('div');
236 statsRow.className = 'bkbg-ghc-stats';
237
238 var statDefs = mode === 'repo'
239 ? [
240 { icon: '', val: formatNumber(data.stargazers_count), lbl: 'stars' },
241 { icon: '🍴', val: formatNumber(data.forks_count), lbl: 'forks' },
242 { icon: '👁', val: formatNumber(data.watchers_count), lbl: 'watchers' }
243 ]
244 : [
245 { icon: '📦', val: formatNumber(data.public_repos), lbl: 'repos' },
246 { icon: '👥', val: formatNumber(data.followers), lbl: 'followers' },
247 { icon: '👤', val: formatNumber(data.following), lbl: 'following' }
248 ];
249
250 statDefs.forEach(function (s) {
251 var tile = document.createElement('div');
252 tile.className = 'bkbg-ghc-stat';
253 tile.style.cssText = 'background:' + statBg + ';border:1px solid ' + borderColor + ';border-radius:8px;';
254
255 var val = document.createElement('span');
256 val.className = 'bkbg-ghc-stat-val';
257 val.style.color = headingColor;
258 val.textContent = s.val;
259
260 var lbl = document.createElement('span');
261 lbl.className = 'bkbg-ghc-stat-lbl';
262 lbl.style.color = metaColor;
263 lbl.textContent = s.lbl;
264
265 tile.appendChild(val);
266 tile.appendChild(lbl);
267 statsRow.appendChild(tile);
268 });
269
270 card.appendChild(statsRow);
271 }
272
273 // Footer - last update
274 if (showLastUpdate) {
275 var updatedAt = mode === 'repo' ? data.pushed_at : data.updated_at;
276 if (updatedAt) {
277 var footer = document.createElement('div');
278 footer.className = 'bkbg-ghc-footer';
279 footer.style.color = metaColor;
280 footer.textContent = formatDate(updatedAt);
281 card.appendChild(footer);
282 }
283 }
284
285 app.appendChild(card);
286 }
287
288 function renderError(msg) {
289 app.removeChild(loading);
290 var err = document.createElement('div');
291 err.className = 'bkbg-ghc-error';
292 err.style.cssText = 'background:' + cardBg + ';border:1px solid #f43f5e;border-radius:' + cardRadius + 'px;max-width:' + maxWidth + 'px;margin:' + (align2 === 'center' ? '0 auto' : align2 === 'right' ? '0 0 0 auto' : '0') + ';color:#f43f5e;';
293 err.textContent = '' + msg;
294 app.appendChild(err);
295 }
296
297 function fetchData() {
298 fetch(apiUrl, { headers: { Accept: 'application/vnd.github.mercy-preview+json' } })
299 .then(function (r) {
300 if (!r.ok) throw new Error('GitHub API returned ' + r.status);
301 return r.json();
302 })
303 .then(function (data) {
304 setCache(cacheKey, data);
305 renderCard(data);
306 })
307 .catch(function (e) {
308 renderError('Could not load GitHub data. ' + e.message);
309 });
310 }
311
312 if (cached) {
313 // Small delay to avoid flicker
314 setTimeout(function () { renderCard(cached); }, 0);
315 } else {
316 fetchData();
317 }
318 });
319 })();
320