Skip to content
Merged
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
11 changes: 7 additions & 4 deletions scripts/update-github-languages.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,18 @@
// user's non-fork repositories (GraphQL, paginated). Needs GITHUB_TOKEN, which
// Actions provides automatically.
import { writeFile } from "node:fs/promises";
import { fetchGitHubLanguages } from "../src/lib/services/github.ts";
import { fetchGitHubCommitTotal, fetchGitHubLanguages } from "../src/lib/services/github.ts";

const username = process.env.GITHUB_USERNAME || "ewanc26";
const token = process.env.GITHUB_TOKEN;
if (!token) throw new Error("GITHUB_TOKEN is required");

const languages = await fetchGitHubLanguages(username, fetch, token);
const [languages, commits] = await Promise.all([
fetchGitHubLanguages(username, fetch, token),
fetchGitHubCommitTotal(username, fetch, token),
]);
if (languages.length === 0) throw new Error("No languages returned; leaving snapshot untouched");

const out = process.env.OUT_FILE || new URL("../src/lib/data/github-languages.json", import.meta.url);
await writeFile(out, JSON.stringify({ username, updatedAt: new Date().toISOString().slice(0, 10), languages }, null, 2) + "\n");
console.log(`Wrote ${languages.length} languages for ${username}`);
await writeFile(out, JSON.stringify({ username, updatedAt: new Date().toISOString().slice(0, 10), commits, languages }, null, 2) + "\n");
console.log(`Wrote ${languages.length} languages and ${commits} commits for ${username}`);
7 changes: 4 additions & 3 deletions src/lib/components/GithubActivity.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
username: string;
contributions: ContributionCalendar | null;
languages: LanguageShare[];
commits?: number | null;
}
let { username, contributions, languages }: Props = $props();
let { username, contributions, languages, commits = null }: Props = $props();

const fmtDate = (iso: string) =>
new Date(`${iso}T00:00:00Z`).toLocaleDateString("en-GB", { day: "numeric", month: "short", year: "numeric", timeZone: "UTC" });
Expand Down Expand Up @@ -57,8 +58,8 @@
{#if contributions && stats}
<dl class="stats">
<div>
<dt class="pix">Contributions</dt>
<dd>{stats.total.toLocaleString("en-GB")}</dd>
<dt class="pix">{commits === null ? "Contributions" : "Commits"}</dt>
<dd>{(commits ?? stats.total).toLocaleString("en-GB")}</dd>
</div>
<div>
<dt class="pix">Days active</dt>
Expand Down
14 changes: 14 additions & 0 deletions src/lib/services/github.ts
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,20 @@ export async function fetchGitHubContributions(
return fetchContributionsFromProfile(username, fetchFn);
}

export async function fetchGitHubCommitTotal(
username: string,
fetchFn: typeof fetch,
token: string,
): Promise<number> {
const data = await graphql(
`query Commits($login: String!) { user(login: $login) { contributionsCollection { totalCommitContributions } } }`,
username,
token,
fetchFn,
);
return data.user.contributionsCollection.totalCommitContributions;
}

const LINGUIST_COLORS: Record<string, string> = {
Assembly: "#6E4C13", Astro: "#ff5a03", Batchfile: "#C1F12E", C: "#555555", "C#": "#178600",
"C++": "#f34b7d", CMake: "#DA3434", CSS: "#663399", Clojure: "#db5855", Dart: "#00B4AB",
Expand Down
29 changes: 19 additions & 10 deletions src/lib/services/home.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,26 +53,34 @@ async function fetchVerifications() {
const LANGUAGE_SNAPSHOT_URL =
"https://raw.githubusercontent.com/ewanc26/website/data/github-languages.json";

type LanguageSnapshot = typeof languageSnapshot;
type LanguageSnapshot = typeof languageSnapshot & { commits?: number | null };

const usable = (snap: LanguageSnapshot | null | undefined, username: string) =>
!!snap &&
snap.username?.toLowerCase() === username.toLowerCase() &&
Array.isArray(snap.languages) &&
snap.languages.length > 0;

async function loadLanguages(username: string) {
async function loadSnapshot(username: string) {
try {
const res = await fetch(LANGUAGE_SNAPSHOT_URL);
if (res.ok) {
const remote = (await res.json()) as LanguageSnapshot;
if (usable(remote, username)) return remote.languages;
if (usable(remote, username)) {
return { languages: remote.languages, commits: remote.commits ?? null };
}
}
} catch {}
if (usable(languageSnapshot, username)) return languageSnapshot.languages;
return fetchGitHubLanguages(username, fetch, env.GITHUB_TOKEN).catch(
() => [],
);
const bundled = languageSnapshot as LanguageSnapshot;
if (usable(bundled, username)) {
return { languages: bundled.languages, commits: bundled.commits ?? null };
}
const languages = await fetchGitHubLanguages(
username,
fetch,
env.GITHUB_TOKEN,
).catch(() => []);
return { languages, commits: null };
}

export async function getHomeData() {
Expand All @@ -85,7 +93,7 @@ export async function getHomeData() {
postsData,
githubProjects,
githubContributions,
githubLanguages,
githubSnapshot,
publicationsData,
links,
] = await Promise.all([
Expand All @@ -107,7 +115,7 @@ export async function getHomeData() {
fetchGitHubContributions(githubUsername, fetch, env.GITHUB_TOKEN).catch(
() => null,
),
loadLanguages(githubUsername),
loadSnapshot(githubUsername),
fetchPublications(PUBLIC_ATPROTO_DID, fetch).catch(() => ({
publications: [],
})),
Expand All @@ -123,7 +131,8 @@ export async function getHomeData() {
githubProjects: githubProjects as any[],
githubUsername,
githubContributions,
githubLanguages,
githubLanguages: githubSnapshot.languages,
githubCommits: githubSnapshot.commits,
publications: (publicationsData?.publications ?? []) as any[],
links: (links ?? { cards: [] }) as { cards: any[] },
};
Expand Down
4 changes: 2 additions & 2 deletions src/routes/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import { PUBLIC_LEAFLET_BLOG_PUBLICATION, PUBLIC_ATPROTO_DID } from "$env/static/public";

let { data } = $props();
const { profile, kibunStatus, musicStatus, posts, githubProjects, githubUsername, githubContributions, githubLanguages, publications, links, apps, watching, feed, latestPlay } = $derived(data);
const { profile, kibunStatus, musicStatus, posts, githubProjects, githubUsername, githubContributions, githubLanguages, githubCommits, publications, links, apps, watching, feed, latestPlay } = $derived(data);

const almanac = $derived(data.almanac);
const esc = (t: string) => t.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
Expand Down Expand Up @@ -233,7 +233,7 @@
{/if}

<SigilRule /><h2 class="word"><span class="word-text" style="--n:7">Commits</span><small>a year of GitHub</small></h2>
<GithubActivity username={githubUsername} contributions={githubContributions} languages={githubLanguages} />
<GithubActivity username={githubUsername} contributions={githubContributions} languages={githubLanguages} commits={githubCommits} />

{#if watching.length > 0}
<SigilRule /><h2 class="word"><span class="word-text" style="--n:8">Watching</span><small>logged on Popfeed</small></h2>
Expand Down
Loading