Skip to content

Commit 75de8a2

Browse files
committed
added github profile preview
1 parent 8631db9 commit 75de8a2

File tree

4 files changed

+472
-0
lines changed

4 files changed

+472
-0
lines changed
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# GitHub Profile Preview App
2+
3+
A simple web application that allows users to search for GitHub profiles and view detailed information about users.
4+
5+
## Features
6+
7+
- Search for GitHub users by username
8+
- View user profile information including:
9+
- Profile picture
10+
- Name and username
11+
- Bio
12+
- Followers and following count
13+
- Number of repositories and gists
14+
- Location
15+
- Company
16+
- Blog/website
17+
- Twitter handle
18+
- Account creation date
19+
- Responsive design that works on mobile and desktop
20+
- Error handling for non-existent users
21+
22+
## Technologies Used
23+
24+
- HTML5
25+
- CSS3 (with Flexbox and Grid layout)
26+
- JavaScript (ES6+)
27+
- GitHub REST API
28+
- Font Awesome for icons
29+
30+
## How to Use
31+
32+
1. Open the `index.html` file in your browser
33+
2. Enter a GitHub username in the search box
34+
3. Click the "Search" button or press Enter
35+
4. View the user's profile information
36+
37+
## API Information
38+
39+
This app uses the GitHub REST API to fetch user data. No API key is required for basic usage, but there are rate limits for unauthenticated requests (60 requests per hour).
40+
41+
API Endpoint used: `https://api.github.com/users/{username}`
42+
43+
## Project Structure
44+
45+
- `index.html` - Main HTML structure
46+
- `style.css` - CSS styling
47+
- `script.js` - JavaScript functionality and API integration
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6+
<title>GitHub Profile Preview |MoizCodeByte</title>
7+
<link rel="stylesheet" href="style.css">
8+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9+
</head>
10+
<body>
11+
<div class="container">
12+
<h1>GitHub Profile Viewer</h1>
13+
<div class="search-container">
14+
<input type="text" id="username" placeholder="Enter GitHub username">
15+
<button id="search-btn">Search</button>
16+
</div>
17+
<div id="profile-container" class="hidden">
18+
<div class="profile-header">
19+
<img id="avatar" src="" alt="User Avatar">
20+
<div class="profile-info">
21+
<h2 id="name"></h2>
22+
<p id="login"></p>
23+
<p id="bio"></p>
24+
<a id="profile-link" href="#" target="_blank">View Profile</a>
25+
</div>
26+
</div>
27+
<div class="stats-container">
28+
<div class="stat">
29+
<i class="fas fa-users"></i>
30+
<span id="followers">0</span>
31+
<p>Followers</p>
32+
</div>
33+
<div class="stat">
34+
<i class="fas fa-user-plus"></i>
35+
<span id="following">0</span>
36+
<p>Following</p>
37+
</div>
38+
<div class="stat">
39+
<i class="fas fa-code-branch"></i>
40+
<span id="repos">0</span>
41+
<p>Repositories</p>
42+
</div>
43+
<div class="stat">
44+
<i class="fas fa-code"></i>
45+
<span id="gists">0</span>
46+
<p>Gists</p>
47+
</div>
48+
</div>
49+
<div class="additional-info">
50+
<div class="info-item" id="location-container">
51+
<i class="fas fa-map-marker-alt"></i>
52+
<span id="location"></span>
53+
</div>
54+
<div class="info-item" id="company-container">
55+
<i class="fas fa-building"></i>
56+
<span id="company"></span>
57+
</div>
58+
<div class="info-item" id="blog-container">
59+
<i class="fas fa-link"></i>
60+
<a id="blog" href="#" target="_blank"></a>
61+
</div>
62+
<div class="info-item" id="twitter-container">
63+
<i class="fab fa-twitter"></i>
64+
<a id="twitter" href="#" target="_blank"></a>
65+
</div>
66+
<div class="info-item" id="created-container">
67+
<i class="fas fa-calendar"></i>
68+
<span id="created-at"></span>
69+
</div>
70+
71+
</div>
72+
</div>
73+
<div id="error-message" class="hidden">
74+
<p>User not found. Please try another username.</p>
75+
</div>
76+
</div>
77+
<script src="script.js"></script>
78+
</body>
79+
</html>
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
document.addEventListener('DOMContentLoaded', () => {
2+
const searchBtn = document.getElementById('search-btn');
3+
const usernameInput = document.getElementById('username');
4+
const profileContainer = document.getElementById('profile-container');
5+
const errorMessage = document.getElementById('error-message');
6+
7+
// Elements for user data
8+
const avatar = document.getElementById('avatar');
9+
const nameElement = document.getElementById('name');
10+
const loginElement = document.getElementById('login');
11+
const bioElement = document.getElementById('bio');
12+
const profileLink = document.getElementById('profile-link');
13+
const followers = document.getElementById('followers');
14+
const following = document.getElementById('following');
15+
const repos = document.getElementById('repos');
16+
const gists = document.getElementById('gists');
17+
const locationElement = document.getElementById('location');
18+
const locationContainer = document.getElementById('location-container');
19+
const companyElement = document.getElementById('company');
20+
const companyContainer = document.getElementById('company-container');
21+
const blogElement = document.getElementById('blog');
22+
const blogContainer = document.getElementById('blog-container');
23+
const twitterElement = document.getElementById('twitter');
24+
const twitterContainer = document.getElementById('twitter-container');
25+
const createdAtElement = document.getElementById('created-at');
26+
const createdContainer = document.getElementById('created-container');
27+
28+
// Add event listeners
29+
searchBtn.addEventListener('click', fetchUserData);
30+
usernameInput.addEventListener('keypress', (e) => {
31+
if (e.key === 'Enter') {
32+
fetchUserData();
33+
}
34+
});
35+
36+
// Fetch user data from GitHub API
37+
async function fetchUserData() {
38+
const username = usernameInput.value.trim();
39+
40+
if (!username) return;
41+
42+
try {
43+
const response = await fetch(`https://api.github.com/users/${username}`);
44+
45+
if (!response.ok) {
46+
throw new Error('User not found');
47+
}
48+
49+
const userData = await response.json();
50+
displayUserData(userData);
51+
profileContainer.classList.remove('hidden');
52+
errorMessage.classList.add('hidden');
53+
} catch (error) {
54+
profileContainer.classList.add('hidden');
55+
errorMessage.classList.remove('hidden');
56+
console.error('Error fetching user data:', error);
57+
}
58+
}
59+
60+
// Display user data in the UI
61+
function displayUserData(user) {
62+
// Set basic user info
63+
avatar.src = user.avatar_url;
64+
nameElement.textContent = user.name || user.login;
65+
loginElement.textContent = `@${user.login}`;
66+
bioElement.textContent = user.bio || 'No bio available';
67+
profileLink.href = user.html_url;
68+
69+
// Set stats
70+
followers.textContent = formatNumber(user.followers);
71+
following.textContent = formatNumber(user.following);
72+
repos.textContent = formatNumber(user.public_repos);
73+
gists.textContent = formatNumber(user.public_gists);
74+
75+
// Set additional info with conditional display
76+
if (user.location) {
77+
locationElement.textContent = user.location;
78+
locationContainer.classList.remove('hidden');
79+
} else {
80+
locationContainer.classList.add('hidden');
81+
}
82+
83+
if (user.company) {
84+
companyElement.textContent = user.company;
85+
companyContainer.classList.remove('hidden');
86+
} else {
87+
companyContainer.classList.add('hidden');
88+
}
89+
90+
if (user.blog) {
91+
blogElement.textContent = formatUrl(user.blog);
92+
blogElement.href = formatUrl(user.blog, true);
93+
blogContainer.classList.remove('hidden');
94+
} else {
95+
blogContainer.classList.add('hidden');
96+
}
97+
98+
if (user.twitter_username) {
99+
twitterElement.textContent = `@${user.twitter_username}`;
100+
twitterElement.href = `https://twitter.com/${user.twitter_username}`;
101+
twitterContainer.classList.remove('hidden');
102+
} else {
103+
twitterContainer.classList.add('hidden');
104+
}
105+
106+
if (user.created_at) {
107+
createdAtElement.textContent = `Joined ${formatDate(user.created_at)}`;
108+
createdContainer.classList.remove('hidden');
109+
} else {
110+
createdContainer.classList.add('hidden');
111+
}
112+
}
113+
114+
// Format numbers for better display (e.g., 1000 -> 1k)
115+
function formatNumber(num) {
116+
if (num >= 1000000) {
117+
return (num / 1000000).toFixed(1) + 'm';
118+
}
119+
if (num >= 1000) {
120+
return (num / 1000).toFixed(1) + 'k';
121+
}
122+
return num;
123+
}
124+
125+
// Format URL for display (remove http/https and trailing slash)
126+
function formatUrl(url, forHref = false) {
127+
if (forHref) {
128+
if (!url.startsWith('http://') && !url.startsWith('https://')) {
129+
return `https://${url}`;
130+
}
131+
return url;
132+
}
133+
134+
return url
135+
.replace(/^https?:\/\//, '')
136+
.replace(/\/$/, '');
137+
}
138+
139+
// Format date to readable format
140+
function formatDate(dateString) {
141+
const options = { year: 'numeric', month: 'short', day: 'numeric' };
142+
return new Date(dateString).toLocaleDateString(undefined, options);
143+
}
144+
});

0 commit comments

Comments
 (0)