Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 56 additions & 20 deletions codewars-badge.js
Original file line number Diff line number Diff line change
@@ -1,50 +1,86 @@
// This native web component fetches data from the Codewars API and renders it as a badge
// Here is some information about web component https://developer.mozilla.org/en-US/docs/Web/Web_Components
// Here is the link to the Codewars API Docs: https://dev.codewars.com/#get-user

class CodeWarsBadge extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: "open" });
this.userName = "CodeYourFuture";
this.userData = [];
this.userName = "Richiealx";
this.userData = null;
}

connectedCallback() {
this.shadowRoot.innerHTML = "<p>Loading badge...</p>";

this.fetchActivity()
.then(() => {
this.render();
})
.catch((error) => {
console.error(error);
this.renderError();
});
}

// fetch the data from the Codewars API
async fetchActivity() {
const response = await fetch(
`https://www.codewars.com/api/v1/users/${this.userName}`
`https://www.codewars.com/api/v1/users/${this.userName}`,
);

if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}

const data = await response.json();
this.userData = data; // set the userData property with the fetched data
this.userData = data;
}

render() {
this.shadowRoot.innerHTML = `
<style>
<style>
:host {
--rank: ${this.userData.ranks.overall.color};
font: 600 100%/1 system-ui, sans-serif;
display: block;
max-width: 420px;
width: 100%;
font: 600 100%/1.4 system-ui, sans-serif;
}

.badge {
border: 2px solid ${this.userData.ranks.overall.color};
border-radius: 10px;
padding: 1rem;
background: #fff;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
text-align: left;
}

h2 {
margin: 0 0 0.75rem;
font-size: 1.8rem;
}

p {
margin: 0.5rem 0;
font-size: 1rem;
}

.rank {
color: ${this.userData.ranks.overall.color};
font-weight: 700;
}
data {
color: var(--rank);
border: 3px solid;
padding: .25em .5em;
}
</style>
<data value="${this.userData.ranks.overall.score}">
${this.userData.ranks.overall.name}
</data>`;

<div class="badge">
<h2>${this.userData.username}</h2>
<p><strong>Rank:</strong> <span class="rank">${this.userData.ranks.overall.name}</span></p>
<p><strong>Score:</strong> ${this.userData.ranks.overall.score}</p>
<p><strong>Honor:</strong> ${this.userData.honor}</p>
<p><strong>Completed Kata:</strong> ${this.userData.codeChallenges.totalCompleted}</p>
</div>
`;
}

renderError() {
this.shadowRoot.innerHTML = `
<p>Failed to load Codewars badge.</p>
`;
}
}

Expand Down
82 changes: 82 additions & 0 deletions codewars-stats.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
class CodewarsStats extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: "open" });
this.userName = "Richiealx";
this.userData = null;
}

connectedCallback() {
this.shadowRoot.innerHTML = "<p>Loading stats...</p>";

this.fetchStats()
.then(() => {
this.render();
})
.catch((error) => {
console.error(error);
this.renderError();
});
}

async fetchStats() {
const response = await fetch(
`https://www.codewars.com/api/v1/users/${this.userName}`,
);

if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}

const data = await response.json();
this.userData = data;
}

render() {
this.shadowRoot.innerHTML = `
<style>
:host {
display: block;
max-width: 420px;
width: 100%;
font: 500 100%/1.4 system-ui, sans-serif;
}

.stats {
border: 1px solid #ccc;
border-radius: 10px;
padding: 1rem;
background: #fff;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
text-align: left;
}

h3 {
margin-top: 0;
margin-bottom: 1rem;
font-size: 1.5rem;
}

p {
margin: 0.5rem 0;
font-size: 1rem;
}
</style>

<div class="stats">
<h3>Codewars Stats</h3>
<p><strong>Total Completed:</strong> ${this.userData.codeChallenges.totalCompleted}</p>
<p><strong>Total Authored:</strong> ${this.userData.codeChallenges.totalAuthored}</p>
<p><strong>Leaderboard Position:</strong> ${this.userData.leaderboardPosition}</p>
</div>
`;
}

renderError() {
this.shadowRoot.innerHTML = `
<p>Failed to load Codewars stats.</p>
`;
}
}

customElements.define("codewars-stats", CodewarsStats);
36 changes: 31 additions & 5 deletions index.html
Original file line number Diff line number Diff line change
@@ -1,17 +1,43 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en-gb">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>Codewars Badge</title>
<meta
name="description"
content="Extending HTML to create a new component"
content="Extending HTML to create reusable web components with Codewars API data"
/>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<script type="module" src="./codewars-badge.js"></script>
<script type="module" src="./codewars-stats.js"></script>
</head>
<body>
<codewars-badge></codewars-badge>
<script async defer type="module" src="./codewars-badge.js"></script>
<body
style="
margin: 0;
font-family: Arial, sans-serif;
background: #f5f5f5;
color: #222;
text-align: center;
padding: 2rem 1rem;
"
>
<main>
<h1>My Codewars Profile</h1>
<p>Reusable web components powered by the Codewars API.</p>

<div
style="
display: flex;
flex-direction: column;
align-items: center;
gap: 20px;
margin-top: 2rem;
"
>
<codewars-badge></codewars-badge>
<codewars-stats></codewars-stats>
</div>
</main>
</body>
</html>