Added 'Git' element gathering information from forgejo and displaying it. Added language-map dependency.

This commit is contained in:
Yohan Boujon 2025-04-05 13:14:55 +02:00
parent 364a680894
commit b2e94296dd
8 changed files with 244 additions and 3 deletions

7
package-lock.json generated
View file

@ -11,6 +11,7 @@
"@jamescoyle/svelte-icon": "^0.1.1",
"@mdi/js": "^7.4.47",
"animejs": "^3.2.2",
"language-map": "^1.5.0",
"svelte2tsx": "^0.7.35"
},
"devDependencies": {
@ -1139,6 +1140,12 @@
"node": ">=6"
}
},
"node_modules/language-map": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/language-map/-/language-map-1.5.0.tgz",
"integrity": "sha512-n7gFZpe+DwEAX9cXVTw43i3wiudWDDtSn28RmdnS/HCPr284dQI/SztsamWanRr75oSlKSaGbV2nmWCTzGCoVg==",
"license": "MIT"
},
"node_modules/locate-character": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz",

View file

@ -24,6 +24,7 @@
"@jamescoyle/svelte-icon": "^0.1.1",
"@mdi/js": "^7.4.47",
"animejs": "^3.2.2",
"language-map": "^1.5.0",
"svelte2tsx": "^0.7.35"
}
}

View file

@ -0,0 +1,95 @@
<script>
import "$lib/css/base.css";
import "$lib/css/git.css";
import { mdiBookmark, mdiHistory, mdiDatabase } from "@mdi/js";
import SvgIcon from "@jamescoyle/svelte-icon";
import { load_api, getCommitCount } from "$lib/ts/load.ts";
import { get_size } from "$lib/ts/size.ts";
import { onMount } from "svelte";
import map from "language-map";
export let repo = "Etheryo/blog";
let loading = true;
let title = repo.split("/")[1];
let commitNum = 0;
let repoSize = 0;
let repoTopics = [];
let repoColors = [];
onMount(async () => {
// Gathering commit number
let response = await getCommitCount(repo);
if (response.error === null) commitNum = response.count;
// Gathering Repository data
response = await load_api(
`https://git.etheryo.fr/api/v1/repos/${repo}`,
);
if (response.error === null) {
repoSize = response.data.size;
repoTopics = response.data.topics;
}
// Gathering Colors for code percentage
response = await load_api(
`https://git.etheryo.fr/api/v1/repos/${repo}/languages`,
);
let lang_percentage = 0.0;
let lang_total = 0;
if (response.error === null) {
for (const [lang, lang_val] of Object.entries(response.data)) {
lang_percentage = lang_val;
repoColors.push({ lang, lang_percentage });
lang_total += lang_val;
}
for (let i = 0; i < repoColors.length; i++) {
repoColors[i].lang_percentage =
Math.round(
(repoColors[i].lang_percentage / lang_total) * 1000,
) / 10;
}
console.log(repoColors);
loading = false;
}
});
</script>
<div
class="git-container flex-col"
role="button"
tabindex="0"
on:click={() => {
window.location.href = `https://git.etheryo.fr/${repo}`;
}}
on:keypress={() => {
window.location.href = `https://git.etheryo.fr/${repo}`;
}}
>
{#if !loading}
<div class="flex-row">
<SvgIcon type="mdi" path={mdiBookmark}></SvgIcon>
<div class="git-commit flex-row">
<p>{get_size(repoSize)}</p>
<SvgIcon type="mdi" path={mdiDatabase}></SvgIcon>
<p>{commitNum}</p>
<SvgIcon type="mdi" path={mdiHistory}></SvgIcon>
</div>
</div>
<h1>{title}</h1>
<div class="git-tag margin-bot-force flex-row">
{#each repoTopics as topic}
<span>{topic}</span>
{/each}
</div>
<div class="git-color flex-row">
{#each repoColors as cl}
<div
style={`width:${cl.lang_percentage}%; background-color: ${map[cl.lang].color};`}
></div>
{/each}
</div>
{:else}
<p>Loading...</p>
{/if}
</div>

View file

@ -29,7 +29,7 @@ h2 {
--color-subtext: #413543;
--color-hiddentext: #AA94AD;
--color-background: #F8F1F1;
--color-code: #ECE6F1;
--color-code: #dcd4e2;
--color-pill: #D0D4CA;
--palette-pink: #ad62aa;
@ -53,8 +53,8 @@ h2 {
--border-max: 2rem;
--profile-content-width-max: 40rem;
--profile-content-width-min: 36rem;
--content-width: 50rem;
--content-height: 52rem;
--content-width: 60rem;
--content-height: 55rem;
--width-min-desktop: 1275px;
--width-mobile: 875px;

75
src/lib/css/git.css Normal file
View file

@ -0,0 +1,75 @@
.git-container {
background-image: var(--background-light);
box-shadow: rgba(79, 50, 93, 0.25) 0px 30px 60px -12px, rgba(0, 0, 0, 0.3) 0px 18px 36px -18px;
border-radius: 1rem;
width: calc(var(--content-width)/3);
height: 10rem;
cursor: pointer;
overflow: hidden;
}
.git-container svg {
width: 3rem;
height: auto;
transform: translate(-2px, -8px);
color: var(--color-subtext);
margin-bottom: 0;
padding-bottom: 0;
}
.git-container h1 {
font-family: "JetBrains Mono";
font-weight: 800;
font-size: 1.4rem;
margin: 1rem;
margin-top: 0;
}
.git-commit {
margin-left: auto;
border-radius: 1rem;
margin-right: 0.3rem;
transition: var(--transition);
}
.git-commit:hover {
background-color: var(--color-code);
}
.git-commit svg {
transform: translate(0);
width: 2rem;
margin-left: 0.3rem;
margin-right: 0.3rem;
}
.git-commit p {
color: var(--color-subtext);
font-family: "JetBrains Mono";
margin: 0;
margin-left: 0.6rem;
user-select: none;
}
.git-tag span {
color: var(--color-text);
background-color: var(--color-pill);
font-family: "JetBrains Mono";
font-weight: 500;
font-size: 0.8rem;
margin-bottom: 1rem;
margin-left: 0.8rem;
padding: 0.4rem;
border-radius: var(--border-min);
}
.git-color {
height: 1rem;
width: 100%;
background-color: red;
}
.git-color > div {
height: 100%;
}

43
src/lib/ts/load.ts Normal file
View file

@ -0,0 +1,43 @@
export async function load_api<T = any>(url: string): Promise<{
data: T | null;
error: Error | null;
}> {
let data: T | null = null;
let error: Error | null = null;
try {
const res = await fetch(url);
if (!res.ok) throw new Error(`Failed to fetch: ${res.status} ${res.statusText}`);
data = await res.json();
} catch (err) {
error = err instanceof Error ? err : new Error('Unknown error');
}
return {
data,
error,
};
}
export async function getCommitCount(repo: string): Promise<{
count: Number | null;
error: Error | null;
}> {
let error = null;
let pageCount = null;
try {
const res = await fetch(`https://git.etheryo.fr//api/v1/repos/${repo}/commits?limit=1&page=1`);
if (!res.ok) throw new Error(`Failed to fetch: ${res.status} ${res.statusText}`);
else pageCount = res.headers.get('X-Pagecount');
}
catch (err) {
error = err instanceof Error ? err : new Error('Unknown error');
}
return {
count: pageCount ? parseInt(pageCount) : null,
error: error,
};
}

16
src/lib/ts/size.ts Normal file
View file

@ -0,0 +1,16 @@
export function get_size(kbytes: number): string {
if (kbytes < 1024) {
return `${kbytes} KiB`;
}
const units = ["MiB", "GiB", "TiB"];
let size = kbytes / 1024;
let unitIndex = 0;
while (size >= 1024 && unitIndex < units.length - 1) {
size /= 1024;
unitIndex++;
}
return `${Math.round(size)} ${units[unitIndex]}`;
}

View file

@ -5,6 +5,7 @@
import CoverImg from "$lib/components/cover-img.svelte";
import Person from "$lib/components/person.svelte";
import Project from "$lib/components/project.svelte";
import Git from "$lib/components/git.svelte";
import topics from "$lib/ts/topic.ts";
@ -57,4 +58,7 @@
<div class="section">
<h1>{hubjson.lab}</h1>
</div>
<Git repo="Etheryo/blog"/>
<Git repo="INSA/assembly_project"/>
<Git repo="Etheryo/curriculum-vitae"/>
</div>