

index.mjs:
import "./styles.css";
let givenProfile = "";
let profileName = "";
let profileId = "";
let profileLink = "";
let profileRepos = "";
let profileFollowers = "";
let profileFollowing = "";
let profileAvatar = "";
let isLoading = false;
let isDarkTheme = true;
// ======== FUNKTSIOONID ========
// Lehe joonistamine/renderdamine
function renderPage() {
document.getElementById("app").innerHTML = `
<div>
<h1>Github profile viewer</h1>
<p>Please enter profile name:</p>
<div class="input-row">
<input value="${givenProfile}" placeholder="Enter GitHub username" />
<button id="clearBtn" title="Clear input">✖️</button>
</div>
<div class="actions-row">
<button id="copyLinkBtn" ${
profileLink ? "" : "disabled"
} title="Copy profile link">📋 Copy Link</button>
<label class="theme-switch">
<input type="checkbox" id="themeToggle" ${
isDarkTheme ? "checked" : ""
}>
<span class="slider"></span>
<span class="label-text">Dark Mode</span>
</label>
</div>
${
isLoading
? '<div class="loading" title="Loading..."></div>'
: `<img id="avatar" src="${
profileAvatar
? profileAvatar
: "https://via.placeholder.com/120?text=No+Avatar"
}" alt="Avatar" />`
}
<div class="content">
<h1 id="name">Name: ${profileName ? profileName : "-"}</h1>
<p id="id">Id: ${profileId ? profileId : "-"}</p>
<p id="repos">Public repos: ${profileRepos ? profileRepos : "-"}</p>
<p id="followers">Followers: ${
profileFollowers ? profileFollowers : "-"
}</p>
<p id="following">Following: ${
profileFollowing ? profileFollowing : "-"
}</p>
<p id="profileurl">Link: ${
profileLink && profileName
? `<a href="${profileLink}" target="_blank" rel="noopener noreferrer">${profileLink}</a>`
: "-"
}</p>
</div>
</div>
`;
const input = document.querySelector("input");
input.addEventListener("change", updateValue);
document.getElementById("clearBtn").addEventListener("click", clearInput);
document
.getElementById("copyLinkBtn")
.addEventListener("click", copyProfileLink);
document
.getElementById("themeToggle")
.addEventListener("change", toggleTheme);
}
// Sisendi muutuste töötlemine
function updateValue(e) {
givenProfile = e.target.value.trim();
fetchProfile();
}
// Andmete tühjendamine
function clearInput() {
givenProfile = "";
profileName = "";
profileId = "";
profileLink = "";
profileRepos = "";
profileFollowers = "";
profileFollowing = "";
profileAvatar = "";
renderPage();
}
// Profiili lingi kopeerimine
function copyProfileLink() {
if (!profileLink) return;
navigator.clipboard.writeText(profileLink).then(() => {
alert("Profile link copied to clipboard!");
});
}
// Teemade vahetamine (tume/hele)
function toggleTheme(e) {
isDarkTheme = e.target.checked;
if (isDarkTheme) {
document.body.classList.add("dark-theme");
document.body.classList.remove("light-theme");
} else {
document.body.classList.add("light-theme");
document.body.classList.remove("dark-theme");
}
}
// GitHub profiili päringu tegemine
async function fetchProfile() {
if (!givenProfile) {
clearInput();
return;
}
isLoading = true;
renderPage();
try {
const response = await fetch(
`https://api.github.com/users/${givenProfile}`
);
const rateLimitRemaining = response.headers.get("X-RateLimit-Remaining");
isLoading = false;
if (!response.ok) {
profileName = "User not found";
profileId = "-";
profileLink = "";
profileRepos = "-";
profileFollowers = "-";
profileFollowing = "-";
profileAvatar = "";
} else {
const data = await response.json();
profileName = data.login || "-";
profileId = data.id || "-";
profileLink = data.html_url || "";
profileRepos = data.public_repos || "-";
profileFollowers = data.followers || "-";
profileFollowing = data.following || "-";
profileAvatar = data.avatar_url || "";
}
if (rateLimitRemaining === "0") {
profileName = "API rate limit reached. Try again later.";
profileId = "";
profileLink = "";
profileRepos = "";
}
renderPage();
} catch (e) {
isLoading = false;
profileName = "Error";
profileId = "-";
profileLink = "";
profileRepos = "-";
profileFollowers = "-";
profileFollowing = "-";
profileAvatar = "";
renderPage();
}
}
// Algne lehe renderdus
renderPage();
styles.css:
body {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
color: #f0f0f0;
margin: 0;
padding: 0;
display: flex;
justify-content: center;
min-height: 100vh;
align-items: center;
font-size: 16px;
user-select: none;
transition: background 0.4s ease, color 0.4s ease;
}
/* Põhikonteiner */
#app > div {
background: rgba(255, 255, 255, 0.12);
backdrop-filter: blur(18px);
border-radius: 18px;
box-shadow: 0 12px 36px rgba(0, 0, 0, 0.4);
padding: 35px 45px;
width: 360px;
max-width: 95vw;
text-align: center;
transition: box-shadow 0.3s ease, transform 0.3s ease;
position: relative;
}
/* Efekt hiirega */
#app > div:hover {
box-shadow: 0 16px 45px rgba(118, 75, 162, 0.75);
transform: translateY(-5px);
}
/* Pealkiri */
h1 {
font-weight: 800;
font-size: 2.4rem;
margin-bottom: 20px;
letter-spacing: 1.4px;
color: #fff;
text-shadow: 0 0 15px #9f7aea;
}
/* Sisendväli */
input {
width: 100%;
padding: 14px 18px;
border-radius: 12px;
border: none;
font-size: 1.05rem;
outline: none;
transition: background-color 0.3s ease, box-shadow 0.4s ease;
margin-bottom: 30px;
box-shadow: inset 0 0 12px rgba(255, 255, 255, 0.25);
background-color: rgba(255, 255, 255, 0.18);
color: #fff;
font-weight: 600;
}
/* Kohatäitja (placeholder) stiil */
input::placeholder {
color: #e3d7ffcc;
font-style: italic;
}
/* Aktiivne sisend */
input:focus {
background-color: rgba(255, 255, 255, 0.35);
box-shadow: 0 0 18px #8b62ff;
}
/* Nupud */
button {
cursor: pointer;
border: none;
border-radius: 10px;
background: #764ba2cc;
color: #fff;
font-weight: 700;
padding: 8px 14px;
margin-left: 10px;
font-size: 1rem;
transition: background-color 0.3s ease;
box-shadow: 0 4px 12px rgba(118, 75, 162, 0.5);
user-select: none;
height: 42px;
}
/* Nupu hover-efekt */
button:hover:not(:disabled) {
background-color: #9f7aea;
box-shadow: 0 6px 18px rgba(159, 122, 234, 0.7);
}
/* Keelatud nupp */
button:disabled {
background-color: #55555555;
cursor: default;
box-shadow: none;
}
/* Sisendi ja nupu rida */
.input-row {
display: flex;
align-items: center;
justify-content: center;
}
/* Toimingute rida */
.actions-row {
margin-bottom: 20px;
display: flex;
justify-content: center;
gap: 15px;
flex-wrap: wrap;
}
/* Teemalüliti */
.theme-switch {
display: flex;
align-items: center;
gap: 8px;
font-weight: 600;
color: #ddd;
user-select: none;
font-size: 0.95rem;
}
/* Peidame checkboxi */
.theme-switch input[type="checkbox"] {
display: none;
}
/* Lüliti taust */
.theme-switch .slider {
width: 44px;
height: 22px;
background-color: #555;
border-radius: 12px;
position: relative;
transition: background-color 0.3s ease;
cursor: pointer;
}
/* Lüliti nupp */
.theme-switch .slider::before {
content: "";
position: absolute;
top: 2px;
left: 2px;
width: 18px;
height: 18px;
background-color: #fff;
border-radius: 50%;
transition: transform 0.3s ease;
}
/* Kui lüliti on aktiveeritud */
.theme-switch input:checked + .slider {
background-color: #764ba2;
}
.theme-switch input:checked + .slider::before {
transform: translateX(22px);
}
/* Profiili info sektsioon */
.content {
margin-top: 15px;
text-align: left;
color: #ddd;
font-weight: 500;
user-select: text;
line-height: 1.5;
}
/* Kasutajanimi */
.content h1#name {
font-size: 1.8rem;
color: #ffd700;
text-shadow: 0 0 10px #ffd700cc;
margin-bottom: 10px;
}
/* Profiili tekst */
.content p {
margin: 8px 0;
font-size: 1.05rem;
display: flex;
align-items: center;
}
/* Ikoonid iga välja ees */
.content p#id::before {
content: "🆔";
margin-right: 8px;
}
.content p#repos::before {
content: "📁";
margin-right: 8px;
}
.content p#followers::before {
content: "👥";
margin-right: 8px;
}
.content p#following::before {
content: "➡️";
margin-right: 8px;
}
.content p#profileurl::before {
content: "🔗";
margin-right: 8px;
}
/* Lingid */
.content a {
color: #ffeb3b;
text-decoration: none;
font-weight: 600;
transition: color 0.3s ease;
word-break: break-word;
}
.content a:hover {
color: #fff176;
text-decoration: underline;
}
/* Avatar */
#avatar {
width: 120px;
height: 120px;
border-radius: 50%;
margin: 0 auto 25px;
box-shadow: 0 0 15px rgba(255, 215, 0, 0.7);
border: 3.5px solid #ffd700;
object-fit: cover;
display: block;
transition: transform 0.4s ease;
}
#avatar:hover {
transform: scale(1.1) rotate(5deg);
}
/* Laadimise animatsioon */
@keyframes pulse {
0%,
100% {
box-shadow: 0 0 15px #764ba2;
}
50% {
box-shadow: 0 0 30px #9f7aea;
}
}
.loading {
width: 40px;
height: 40px;
border-radius: 50%;
margin: 0 auto 20px;
background: #764ba2;
animation: pulse 1.5s infinite ease-in-out;
box-shadow: 0 0 15px #764ba2;
}
p#profileurl {
word-break: break-all;
}
/* Hele teema */
body.light-theme {
background: linear-gradient(135deg, #f0f0f0 0%, #d1d1d1 100%);
color: #222;
}
body.light-theme #app > div {
background: rgba(255, 255, 255, 0.9);
color: #222;
box-shadow: 0 12px 36px rgba(0, 0, 0, 0.1);
}
body.light-theme input {
background-color: #fff;
color: #333;
box-shadow: inset 0 0 12px rgba(0, 0, 0, 0.1);
}
body.light-theme input::placeholder {
color: #888;
font-style: normal;
}
body.light-theme input:focus {
background-color: #f0f0f0;
box-shadow: 0 0 12px #764ba2;
}
body.light-theme button {
background: #764ba2;
color: #fff;
box-shadow: 0 4px 12px rgba(118, 75, 162, 0.3);
}
body.light-theme button:hover:not(:disabled) {
background-color: #9f7aea;
box-shadow: 0 6px 18px rgba(159, 122, 234, 0.5);
}
body.light-theme .theme-switch {
color: #444;
}
body.light-theme .content a {
color: #764ba2;
}
body.light-theme .content a:hover {
color: #9f7aea;
}
/* Mobiilne kohandamine */
@media (max-width: 420px) {
#app > div {
padding: 25px 30px;
width: 95vw;
}
h1 {
font-size: 2rem;
}
#avatar {
width: 100px;
height: 100px;
margin-bottom: 20px;
}
button {
margin-left: 5px;
padding: 8px 10px;
}
}

Kokkuvõte:
- renderPage() – loob ja uuendab veebilehe sisu
- updateValue() – jälgib sisestusvälja muutusi
- fetchProfile() – teostab API päringud ja töödeldab vastused
On loodud leht mis teeb päringud GitHubi ja näitab valiku infot (ID, repos number, followers,followings ja link Githubile)