Skip to content

Commit f5280c3

Browse files
committed
Add exclude parameter to createRepoWidget for filtering repositories
1 parent 05928f9 commit f5280c3

4 files changed

Lines changed: 189 additions & 180 deletions

File tree

codepen/repoWidget.js

Lines changed: 176 additions & 179 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,53 @@
11
(function () {
2-
function createRepoWidget({
3-
username, // GitHub username
4-
containerId, // ID of the container element
5-
columns = { mobile: 1, tablet: 2, desktop: 3 },
6-
cardStyles = {}, // Optional custom styles for the card background and container
7-
textStyles = {}, // Optional custom styles for text and icon colors
8-
scaleOnHover = 1.05, // Default scale factor on hover; set to 0 or false to disable
9-
maxRepos = columns.desktop === 1 ? 10 : columns.desktop * 2, // Default maxRepos is double the desktop column count
10-
sortBy = 'stars', // Sorting parameter; options: "stars", "forks", "size", "name", "updated"
11-
}) {
12-
const repoContainer = document.getElementById(containerId);
13-
14-
const languageColors = {
15-
JavaScript: '#f1e05a',
16-
Python: '#3572A5',
17-
TypeScript: '#2b7489',
18-
Vue: '#41b883',
19-
React: '#61DAFB',
20-
Angular: '#E53238',
21-
Node: '#339933',
22-
Express: '#000000',
23-
Django: '#092E20',
24-
CSS: '#563d7c',
25-
HTML: '#e34c26',
26-
Java: '#b07219',
27-
C: '#555555',
28-
'C#': '#178600',
29-
'C++': '#f34b7d',
30-
Go: '#00add8',
31-
Ruby: '#701516',
32-
PHP: '#4F5D95',
33-
Swift: '#ffac45',
34-
Kotlin: '#F18E33',
35-
Rust: '#dea584',
36-
SQL: '#e38c00',
37-
MySQL: '#4479A1',
38-
PostgreSQL: '#336791',
39-
MongoDB: '#47A248',
40-
Docker: '#2496ED',
41-
GitHub: '#181717',
42-
Azure: '#0078D4',
43-
AWS: '#FF9900',
44-
};
45-
46-
repoContainer.style.display = 'grid';
47-
repoContainer.style.gap = '16px';
48-
49-
const styles = `
2+
function createRepoWidget({
3+
username, // GitHub username
4+
containerId, // ID of the container element
5+
columns = { mobile: 1, tablet: 2, desktop: 3 },
6+
cardStyles = {}, // Optional custom styles for the card background and container
7+
textStyles = {}, // Optional custom styles for text and icon colors
8+
scaleOnHover = 1.05, // Default scale factor on hover; set to 0 or false to disable
9+
maxRepos = columns.desktop === 1 ? 10 : columns.desktop * 2, // Default maxRepos is double the desktop column count
10+
sortBy = 'stars', // Sorting parameter; options: "stars", "forks", "size", "name", "updated"
11+
exclude = [], // Array of repository names to exclude
12+
}) {
13+
const repoContainer = document.getElementById(containerId);
14+
15+
const languageColors = {
16+
JavaScript: '#f1e05a',
17+
Python: '#3572A5',
18+
TypeScript: '#2b7489',
19+
Vue: '#41b883',
20+
React: '#61DAFB',
21+
Angular: '#E53238',
22+
Node: '#339933',
23+
Express: '#000000',
24+
Django: '#092E20',
25+
CSS: '#563d7c',
26+
HTML: '#e34c26',
27+
Java: '#b07219',
28+
C: '#555555',
29+
'C#': '#178600',
30+
'C++': '#f34b7d',
31+
Go: '#00add8',
32+
Ruby: '#701516',
33+
PHP: '#4F5D95',
34+
Swift: '#ffac45',
35+
Kotlin: '#F18E33',
36+
Rust: '#dea584',
37+
SQL: '#e38c00',
38+
MySQL: '#4479A1',
39+
PostgreSQL: '#336791',
40+
MongoDB: '#47A248',
41+
Docker: '#2496ED',
42+
GitHub: '#181717',
43+
Azure: '#0078D4',
44+
AWS: '#FF9900',
45+
};
46+
47+
repoContainer.style.display = 'grid';
48+
repoContainer.style.gap = '16px';
49+
50+
const styles = `
5051
#${containerId} {
5152
grid-template-columns: repeat(${columns.mobile}, 1fr);
5253
}
@@ -62,166 +63,162 @@
6263
}
6364
`;
6465

65-
const styleSheet = document.createElement('style');
66-
styleSheet.innerText = styles;
67-
document.head.appendChild(styleSheet);
68-
69-
// Cache response for 1 day
70-
const CACHE_EXPIRATION = 24 * 60 * 60 * 1000;
71-
72-
// async function fetchCommitCount(repo) {
73-
// const response = await fetch(
74-
// `https://api.github.com/repos/${repo.owner.login}/${repo.name}/commits`
75-
// );
76-
// if (!response.ok) {
77-
// console.error('GitHub API error:', response.statusText);
78-
// return 0;
79-
// }
80-
// const commits = await response.json();
81-
// return commits.length;
82-
// }
83-
84-
async function fetchRepos() {
85-
const cacheKey = `repos_${username}`;
86-
const cachedData = localStorage.getItem(cacheKey);
87-
const cachedETag = localStorage.getItem(`${cacheKey}_etag`);
88-
const cacheTimestamp = localStorage.getItem(`${cacheKey}_timestamp`);
89-
const now = Date.now();
90-
const headers = {};
91-
92-
if (cachedETag) {
93-
headers['If-None-Match'] = cachedETag;
94-
}
95-
96-
const response = await fetch(`https://api.github.com/users/${username}/repos`, {
97-
headers,
98-
});
99-
100-
if (response.status === 304 && cachedData) {
101-
return JSON.parse(cachedData);
102-
}
103-
104-
if (!response.ok) {
105-
console.error('GitHub API error:', response.statusText);
106-
return [];
107-
}
108-
109-
const repos = await response.json();
110-
const eTag = response.headers.get('ETag');
111-
112-
// for (const repo of repos) {
113-
// repo.commit_count = await fetchCommitCount(repo);
114-
// }
115-
116-
localStorage.setItem(cacheKey, JSON.stringify(repos));
117-
localStorage.setItem(`${cacheKey}_timestamp`, now);
118-
if (eTag) {
119-
localStorage.setItem(`${cacheKey}_etag`, eTag);
120-
}
121-
122-
return repos;
123-
}
124-
125-
// Sort repositories based on the provided sortBy parameter
126-
function sortRepositories(repos) {
127-
switch (sortBy) {
128-
case 'stars':
129-
return repos.sort((a, b) => b.stargazers_count - a.stargazers_count);
130-
case 'forks':
131-
return repos.sort((a, b) => b.forks_count - a.forks_count);
132-
case 'size':
133-
return repos.sort((a, b) => b.size - a.size);
134-
case 'name':
135-
return repos.sort((a, b) => a.name.localeCompare(b.name));
136-
case 'updated':
137-
return repos.sort((a, b) => new Date(b.updated_at) - new Date(a.updated_at));
138-
// case 'commits':
139-
// return repos.sort((a, b) => b.commit_count - a.commit_count);
140-
default:
141-
return repos;
142-
}
143-
}
144-
145-
async function initializeWidget() {
146-
let repos = await fetchRepos();
147-
repos = sortRepositories(repos).slice(0, maxRepos);
148-
149-
const fragment = document.createDocumentFragment();
150-
151-
repos.forEach((repo) => {
152-
const card = document.createElement('article');
153-
card.setAttribute('role', 'region');
154-
card.setAttribute('aria-labelledby', `repo-title-${repo.name}`);
155-
card.style.cssText = `
66+
const styleSheet = document.createElement('style');
67+
styleSheet.innerText = styles;
68+
document.head.appendChild(styleSheet);
69+
70+
// Cache response for 1 day
71+
const CACHE_EXPIRATION = 24 * 60 * 60 * 1000;
72+
73+
// async function fetchCommitCount(repo) {
74+
// const response = await fetch(
75+
// `https://api.github.com/repos/${repo.owner.login}/${repo.name}/commits`
76+
// );
77+
// if (!response.ok) {
78+
// console.error('GitHub API error:', response.statusText);
79+
// return 0;
80+
// }
81+
// const commits = await response.json();
82+
// return commits.length;
83+
// }
84+
85+
async function fetchRepos() {
86+
const cacheKey = `repos_${username}`;
87+
const cachedData = localStorage.getItem(cacheKey);
88+
const cachedETag = localStorage.getItem(`${cacheKey}_etag`);
89+
const cacheTimestamp = localStorage.getItem(`${cacheKey}_timestamp`);
90+
const now = Date.now();
91+
const headers = {};
92+
93+
if (cachedETag) {
94+
headers['If-None-Match'] = cachedETag;
95+
}
96+
97+
const response = await fetch(`https://api.github.com/users/${username}/repos`, {
98+
headers,
99+
});
100+
101+
if (response.status === 304 && cachedData) {
102+
return JSON.parse(cachedData);
103+
}
104+
105+
if (!response.ok) {
106+
console.error('GitHub API error:', response.statusText);
107+
return [];
108+
}
109+
110+
const repos = await response.json();
111+
const eTag = response.headers.get('ETag');
112+
113+
// for (const repo of repos) {
114+
// repo.commit_count = await fetchCommitCount(repo);
115+
// }
116+
117+
localStorage.setItem(cacheKey, JSON.stringify(repos));
118+
localStorage.setItem(`${cacheKey}_timestamp`, now);
119+
if (eTag) {
120+
localStorage.setItem(`${cacheKey}_etag`, eTag);
121+
}
122+
123+
return repos;
124+
}
125+
126+
// Sort repositories based on the provided sortBy parameter
127+
function sortRepositories(repos) {
128+
switch (sortBy) {
129+
case 'stars':
130+
return repos.sort((a, b) => b.stargazers_count - a.stargazers_count);
131+
case 'forks':
132+
return repos.sort((a, b) => b.forks_count - a.forks_count);
133+
case 'size':
134+
return repos.sort((a, b) => b.size - a.size);
135+
case 'name':
136+
return repos.sort((a, b) => a.name.localeCompare(b.name));
137+
case 'updated':
138+
return repos.sort((a, b) => new Date(b.updated_at) - new Date(a.updated_at));
139+
// case 'commits':
140+
// return repos.sort((a, b) => b.commit_count - a.commit_count);
141+
default:
142+
return repos;
143+
}
144+
}
145+
146+
async function initializeWidget() {
147+
let repos = await fetchRepos();
148+
149+
if (exclude && exclude.length > 0) {
150+
repos = repos.filter((repo) => !exclude.includes(repo.name));
151+
}
152+
153+
repos = sortRepositories(repos).slice(0, maxRepos);
154+
155+
const fragment = document.createDocumentFragment();
156+
157+
repos.forEach((repo) => {
158+
const card = document.createElement('article');
159+
card.setAttribute('role', 'region');
160+
card.setAttribute('aria-labelledby', `repo-title-${repo.name}`);
161+
card.style.cssText = `
156162
background: #fff;
157163
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
158164
border-radius: 8px;
159165
overflow: hidden;
160166
transition: transform 0.3s;
161167
`;
162168

163-
Object.assign(card.style, cardStyles);
169+
Object.assign(card.style, cardStyles);
164170

165-
if (scaleOnHover) {
166-
card.onmouseover = () => (card.style.transform = `scale(${scaleOnHover})`);
167-
card.onmouseleave = () => (card.style.transform = 'scale(1)');
168-
}
171+
if (scaleOnHover) {
172+
card.onmouseover = () => (card.style.transform = `scale(${scaleOnHover})`);
173+
card.onmouseleave = () => (card.style.transform = 'scale(1)');
174+
}
169175

170-
const languageColor = languageColors[repo.language] || '#cccccc';
176+
const languageColor = languageColors[repo.language] || '#cccccc';
171177

172-
card.innerHTML = `
173-
<a href="${
174-
repo.html_url
175-
}" target="_blank" style="text-decoration: none; color: inherit; display: flex; flex-direction: column; height: 100%; padding: 16px;" aria-label="Repository ${
176-
repo.name
177-
}">
178+
card.innerHTML = `
179+
<a href="${repo.html_url
180+
}" target="_blank" style="text-decoration: none; color: inherit; display: flex; flex-direction: column; height: 100%; padding: 16px;" aria-label="Repository ${repo.name
181+
}">
178182
<div style="flex: 1;">
179-
<h3 id="repo-title-${
180-
repo.name
181-
}" style="font-size: 1.25rem; font-weight: bold; color: ${
182-
textStyles.titleColor || '#333333'
183-
};">${repo.name}</h3>
184-
<p style="color: ${textStyles.descriptionColor || '#666666'}; margin: 8px 0;">${
185-
repo.description || 'No description provided'
186-
}</p>
183+
<h3 id="repo-title-${repo.name
184+
}" style="font-size: 1.25rem; font-weight: bold; color: ${textStyles.titleColor || '#333333'
185+
};">${repo.name}</h3>
186+
<p style="color: ${textStyles.descriptionColor || '#666666'}; margin: 8px 0;">${repo.description || 'No description provided'
187+
}</p>
187188
</div>
188189
<div style="margin-top: auto;">
189-
<div style="display: flex; align-items: center; color: ${
190-
textStyles.iconColor || '#888888'
191-
}; font-size: 0.875rem;">
190+
<div style="display: flex; align-items: center; color: ${textStyles.iconColor || '#888888'
191+
}; font-size: 0.875rem;">
192192
<span style="display: flex; align-items: center; margin-right: 16px;">
193193
<span style="width: 10px; height: 10px; background-color: ${languageColor}; border-radius: 50%; margin-right: 4px;"></span>
194194
${repo.language || 'N/A'}
195195
</span>
196196
<span style="display: flex; align-items: center; margin-right: 16px;">
197-
<svg width="16" height="16" fill="${
198-
textStyles.iconColor || '#888888'
199-
}" style="margin-right: 4px;"><path d="M5 5.372v.878c0 .414.336.75.75.75h4.5a.75.75 0 0 0 .75-.75v-.878a2.25 2.25 0 1 1 1.5 0v.878a2.25 2.25 0 0 1-2.25 2.25h-1.5v2.128a2.251 2.251 0 1 1-1.5 0V8.5h-1.5A2.25 2.25 0 0 1 3.5 6.25v-.878a2.25 2.25 0 1 1 1.5 0ZM5 3.25a.75.75 0 1 0-1.5 0 .75.75 0 0 0 1.5 0Zm6.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm-3 8.75a.75.75 0 1 0-1.5 0 .75.75 0 0 0 1.5 0Z"></path></svg>
197+
<svg width="16" height="16" fill="${textStyles.iconColor || '#888888'
198+
}" style="margin-right: 4px;"><path d="M5 5.372v.878c0 .414.336.75.75.75h4.5a.75.75 0 0 0 .75-.75v-.878a2.25 2.25 0 1 1 1.5 0v.878a2.25 2.25 0 0 1-2.25 2.25h-1.5v2.128a2.251 2.251 0 1 1-1.5 0V8.5h-1.5A2.25 2.25 0 0 1 3.5 6.25v-.878a2.25 2.25 0 1 1 1.5 0ZM5 3.25a.75.75 0 1 0-1.5 0 .75.75 0 0 0 1.5 0Zm6.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm-3 8.75a.75.75 0 1 0-1.5 0 .75.75 0 0 0 1.5 0Z"></path></svg>
200199
${repo.forks_count}
201200
</span>
202201
<span style="display: flex; align-items: center;">
203-
<svg width="16" height="16" fill="${
204-
textStyles.iconColor || '#888888'
205-
}" style="margin-right: 4px;"><path d="M8 .25a.75.75 0 0 1 .673.418l1.882 3.815 4.21.612a.75.75 0 0 1 .416 1.279l-3.046 2.97.719 4.192a.751.751 0 0 1-1.088.791L8 12.347l-3.766 1.98a.75.75 0 0 1-1.088-.79l.72-4.194L.818 6.374a.75.75 0 0 1 .416-1.28l4.21-.611L7.327.668A.75.75 0 0 1 8 .25Z"></path></svg>
202+
<svg width="16" height="16" fill="${textStyles.iconColor || '#888888'
203+
}" style="margin-right: 4px;"><path d="M8 .25a.75.75 0 0 1 .673.418l1.882 3.815 4.21.612a.75.75 0 0 1 .416 1.279l-3.046 2.97.719 4.192a.751.751 0 0 1-1.088.791L8 12.347l-3.766 1.98a.75.75 0 0 1-1.088-.79l.72-4.194L.818 6.374a.75.75 0 0 1 .416-1.28l4.21-.611L7.327.668A.75.75 0 0 1 8 .25Z"></path></svg>
206204
${repo.stargazers_count}
207205
</span>
208206
</div>
209-
<div style="color: ${
210-
textStyles.sizeColor || '#aaaaaa'
211-
}; font-size: 0.75rem; margin-top: 8px;">Size: ${repo.size} KB</div>
207+
<div style="color: ${textStyles.sizeColor || '#aaaaaa'
208+
}; font-size: 0.75rem; margin-top: 8px;">Size: ${repo.size} KB</div>
212209
</div>
213210
</a>
214211
`;
215212

216-
fragment.appendChild(card);
217-
});
213+
fragment.appendChild(card);
214+
});
218215

219-
repoContainer.innerHTML = '';
220-
repoContainer.appendChild(fragment);
221-
}
216+
repoContainer.innerHTML = '';
217+
repoContainer.appendChild(fragment);
218+
}
222219

223-
initializeWidget();
224-
}
220+
initializeWidget();
221+
}
225222

226-
window.createRepoWidget = createRepoWidget;
223+
window.createRepoWidget = createRepoWidget;
227224
})();

0 commit comments

Comments
 (0)