Skip to content
16 changes: 14 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
<div>
<h1 align="center">github-card 🌈</h1>
<p align="center">Beautiful embeddable GitHub profile card for your portfolio. <br/>
Here is a live <a href="https://codepen.io/RocktimSaikia/full/jObbBmR">codepen Demo</a></p>
<a href="https://rocktimsaikia.github.io/github-card/">https://rocktimsaikia.github.io/github-card/</a></p>
<p align="center">
<a href="https://github.com/rocktimsaikia/github-card/actions/workflows/main.yml"><img alt="CI" src="https://github.com/rocktimsaikia/github-card/actions/workflows/main.yml/badge.svg"/></a>
<a href="https://www.npmjs.com/package/@rocktimsaikia/github-card"><img src="https://badge.fury.io/js/%40rocktimsaikia%2Fgithub-card.svg" alt="npm version"></a>
</p>
<p align="center"><a href="https://codepen.io/RocktimSaikia/full/jObbBmR"><img src="https://i.ibb.co/LdZZMdr/github-card.png"/></a></p>
<p align="center"><a href="https://rocktimsaikia.github.io/github-card/"><img src="https://i.ibb.co/LdZZMdr/github-card.png"/></a></p>
</div>


Expand Down Expand Up @@ -61,6 +61,18 @@ Or skip the install and load it straight from a CDN in an HTML file:
<github-card data-user="rocktimsaikia" data-theme="dark"></github-card>
```

## Customization

Override the accent color with the `--gh-accent` CSS custom property on the element:

```css
github-card {
--gh-accent: #6366f1;
}
```

The card also surfaces `location`, `company`, and `website` from the GitHub profile when present.

## License

2026 © MIT [Rocktim Saikia](https://rocktimcodes.site)
119 changes: 98 additions & 21 deletions examples/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,108 @@
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Github-card</title>
</head>
<style>
.profile {
display: flex;
justify-content: center;
margin-top: 50px;
}
.profile div {
margin: 20px;
}

@media screen and (max-width: 992px) {
.profile {
<title>github-card — demo</title>
<style>
body {
font-family:
-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
margin: 0;
padding: 48px 16px;
background: #fafbfc;
color: #1f2328;
}
h1 {
margin: 0 0 4px;
text-align: center;
font-size: 22px;
}
.subtitle {
margin: 0 0 44px;
text-align: center;
font-size: 14px;
color: #57606a;
}
.grid {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 44px 32px;
}
figure {
display: flex;
flex-direction: column;
align-items: center;
gap: 14px;
margin: 0;
max-width: 320px;
}
figcaption {
text-align: center;
}
figcaption strong {
display: block;
margin-bottom: 8px;
font-size: 14px;
}
}
</style>
figcaption code {
display: inline-block;
margin: 2px;
padding: 3px 8px;
border-radius: 6px;
background: #eaeef2;
font-size: 12px;
color: #1f2328;
}
</style>
</head>
<body>
<div class="profile">
<github-card data-user="benawad" data-theme="dark"></github-card>
<github-card data-user="rocktimsaikia"></github-card>
<github-card data-user="sindresorhus" data-theme="dark"></github-card>
<h1>github-card</h1>
<p class="subtitle">
Each example below shows the exact attributes the card is using.
</p>

<div class="grid">
<figure>
<github-card data-user="rocktimsaikia"></github-card>
<figcaption>
<strong>Default · light theme</strong>
<code>data-user="rocktimsaikia"</code>
</figcaption>
</figure>

<figure>
<github-card data-user="benawad" data-theme="dark"></github-card>
<figcaption>
<strong>Dark theme</strong>
<code>data-theme="dark"</code>
</figcaption>
</figure>

<figure>
<github-card
data-user="sindresorhus"
style="--gh-accent: #6366f1"
></github-card>
<figcaption>
<strong>Custom accent</strong>
<code>style="--gh-accent: #6366f1"</code>
</figcaption>
</figure>

<figure>
<github-card
data-user="gaearon"
data-theme="dark"
style="--gh-accent: #22c55e"
></github-card>
<figcaption>
<strong>Dark + custom accent</strong>
<code>data-theme="dark"</code>
<code>--gh-accent: #22c55e</code>
</figcaption>
</figure>
</div>

<script type="module" src="../dist/index.js"></script>
<!-- <script type="module" src="https://unpkg.com/@rocktimsaikia/github-card@latest?module"></script> -->
</body>
</html>
91 changes: 63 additions & 28 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
import escapeHtml from './escape.js';
import nFormatter from './format.js';
import widgetStyle from './style.js';
import safeUrl from './url.js';

// Inline monochrome icons (Material Symbols) for the profile meta row.
const ICON_LOCATION =
'<svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7zm0 9.5a2.5 2.5 0 1 1 0-5 2.5 2.5 0 0 1 0 5z"/></svg>';
const ICON_COMPANY =
'<svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 7V3H2v18h20V7H12zM6 19H4v-2h2v2zm0-4H4v-2h2v2zm0-4H4V9h2v2zm0-4H4V5h2v2zm4 12H8v-2h2v2zm0-4H8v-2h2v2zm0-4H8V9h2v2zm0-4H8V5h2v2zm10 12h-8v-2h2v-2h-2v-2h2v-2h-2V9h8v10zm-2-8h-2v2h2v-2zm0 4h-2v2h2v-2z"/></svg>';
const ICON_LINK =
'<svg viewBox="0 0 24 24" fill="currentColor"><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76 0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71 0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71 0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76 0 5-2.24 5-5s-2.24-5-5-5z"/></svg>';

const template = document.createElement('template');

Expand Down Expand Up @@ -60,35 +69,61 @@ class myCard extends HTMLElement {
const login = escapeHtml(user.login);
const htmlUrl = escapeHtml(user.html_url);
const name = escapeHtml(user.name);
const bio = escapeHtml(user.bio ?? '');
const bioHtml = user.bio
? `<p class="card-desc">${escapeHtml(user.bio)}</p>`
: '';

const meta = [];
if (user.location) {
meta.push(
`<span class="meta-item">${ICON_LOCATION}${escapeHtml(user.location)}</span>`,
);
}
if (user.company) {
meta.push(
`<span class="meta-item">${ICON_COMPANY}${escapeHtml(user.company)}</span>`,
);
}
const blog = safeUrl(user.blog);
if (blog) {
const label = escapeHtml(String(user.blog).replace(/^https?:\/\//i, ''));
meta.push(
`<a class="meta-item meta-link" href="${escapeHtml(blog)}" target="_blank" rel="noopener">${ICON_LINK}${label}</a>`,
);
}
const metaHtml = meta.length
? `<div class="card-meta">${meta.join('')}</div>`
: '';

return `
<div class="cover"></div>
<div class="card-wrapper">
<a href="https://github.com/${login}" target="_blank" rel="noopener"><img id="github-logo" src="https://i.ibb.co/frv5pB3/github-logo.png" alt="github-logo" border="0"></a>
<div class="card-header">
<div class="card-img-wrapper"><img src="https://avatars.githubusercontent.com/${login}" alt="${name}"/></div>
<h1><a class="card-title" href="${htmlUrl}" target="_blank" rel="noopener">${name}</a></h1>
<div class="card-responsename"><a href="${htmlUrl}" target="_blank" rel="noopener">@${login}</a></div>
<p class="card-desc">${bio}</p>
<div class="card-footer">
<div class="footer-box">
<div class="box-wrapper">
<div class="count">${nFormatter(user.followers)}</div>
<div class="box-text">Followers</div>
</div>
<div class="box-wrapper">
<div class="count">${nFormatter(user.following)}</div>
<div class="box-text">Following</div>
</div>
<div class="box-wrapper">
<div class="count">${nFormatter(user.public_repos)}</div>
<div class="box-text">Repositories</div>
</div>
</div>
</div>
</div>
</div>
`;
<div class="cover"></div>
<div class="card-wrapper">
<a href="https://github.com/${login}" target="_blank" rel="noopener"><img id="github-logo" src="https://i.ibb.co/frv5pB3/github-logo.png" alt="github-logo" border="0"></a>
<div class="card-header">
<div class="card-img-wrapper"><img src="https://avatars.githubusercontent.com/${login}" alt="${name}"/></div>
<h1><a class="card-title" href="${htmlUrl}" target="_blank" rel="noopener">${name}</a></h1>
<div class="card-responsename"><a href="${htmlUrl}" target="_blank" rel="noopener">@${login}</a></div>
${bioHtml}
${metaHtml}
<div class="card-footer">
<div class="footer-box">
<div class="box-wrapper">
<div class="count">${nFormatter(user.followers)}</div>
<div class="box-text">Followers</div>
</div>
<div class="box-wrapper">
<div class="count">${nFormatter(user.following)}</div>
<div class="box-text">Following</div>
</div>
<div class="box-wrapper">
<div class="count">${nFormatter(user.public_repos)}</div>
<div class="box-text">Repos</div>
</div>
</div>
</div>
</div>
</div>
`;
}
}

Expand Down
Loading
Loading