Compare commits

..

3 commits

7 changed files with 179 additions and 24 deletions

View file

@ -5,14 +5,20 @@
import { mdiBookmark, mdiHistory, mdiDatabase } from "@mdi/js";
import SvgIcon from "@jamescoyle/svelte-icon";
// TS Scripts
import { load_api, getCommitCount } from "$lib/ts/load.ts";
import { get_size } from "$lib/ts/size.ts";
import { LoadingSkeleton, Loading } from "$lib/ts/loading.ts";
import viewport from "$lib/ts/viewport.ts";
import { onMount } from "svelte";
import map from "language-map";
import anime from "animejs";
import { redirect } from "@sveltejs/kit";
// Exported values/ Internal values
export let repo = "Etheryo/blog";
let loading = true;
let title = repo.split("/")[1];
let commitNum = 0;
let repoSize = 0;
@ -23,7 +29,12 @@
repoSize: 0,
};
let overlay_div;
// Loading logic
let finishLoading = new Loading();
let finishLoadingStatus = false;
// Mouse animation
let overlayDiv;
let cursorX = 0;
let cursorY = 0;
let updateX = true;
@ -33,7 +44,7 @@
cursorX = event.clientX - rect.left;
}
cursorY = event.clientY - rect.top;
overlay_div.style.backgroundImage = `radial-gradient(circle farthest-corner at ${Math.floor(cursorX)}px ${Math.floor(cursorY)}px, var(--color-background) 0%, #958a98 100%)`;
overlayDiv.style.backgroundImage = `radial-gradient(circle farthest-corner at ${Math.floor(cursorX)}px ${Math.floor(cursorY)}px, var(--color-background) 0%, #958a98 100%)`;
}
function animateForeground(isEntering, div_back) {
@ -47,7 +58,15 @@
});
}
// Loading animation
let divLoading;
let skeleton;
let countersSet = false;
onMount(async () => {
skeleton = new LoadingSkeleton(divLoading);
skeleton.start();
// Gathering commit number
let response = await getCommitCount(repo);
if (response.error === null) commitNum = response.count;
@ -79,9 +98,13 @@
(repoColors[i].lang_percentage / lang_total) * 1000,
) / 10;
}
loading = false;
await skeleton.stop();
finishLoadingStatus = finishLoading.setStatus(true);
}
});
async function animateCounters() {
await finishLoading.getPromise();
// Animation for counters
anime({
targets: { num: 0 },
@ -107,7 +130,8 @@
);
},
});
});
countersSet = true;
}
</script>
<div
@ -115,13 +139,13 @@
role="button"
tabindex="0"
on:mousemove={(event) => {
update_gradient(event, overlay_div);
update_gradient(event, overlayDiv);
}}
on:mouseenter={() => {
animateForeground(true, overlay_div);
animateForeground(true, overlayDiv);
}}
on:mouseleave={() => {
animateForeground(false, overlay_div);
animateForeground(false, overlayDiv);
}}
on:click={() => {
window.location.href = `https://git.etheryo.fr/${repo}`;
@ -129,9 +153,13 @@
on:keypress={() => {
window.location.href = `https://git.etheryo.fr/${repo}`;
}}
use:viewport
on:enterViewport={() => {
if (!countersSet) animateCounters();
}}
>
<div class="git-container overlay">
{#if !loading}
{#if finishLoadingStatus}
<div class="flex-row">
<SvgIcon type="mdi" path={mdiBookmark}></SvgIcon>
<div class="git-commit flex-row">
@ -156,9 +184,9 @@
{/each}
</div>
{:else}
<p>Loading...</p>
<div class="git-loading w-100 h-100" bind:this={divLoading}></div>
{/if}
</div>
<div class="overlay-front"></div>
<div class="overlay-back" bind:this={overlay_div}></div>
<div class="overlay-back" bind:this={overlayDiv}></div>
</div>

View file

@ -84,11 +84,10 @@ h2 {
margin: 0;
}
.section::after {
.section h1::after {
width: 50%;
height: 2px;
left: 2rem;
bottom: 0.75rem;
bottom: -0.5rem;
content: "";
position: relative;
display: block;
@ -104,6 +103,15 @@ h2 {
margin: 2rem;
}
.section p {
color: var(--color-subtext);
font-family: "JetBrains Mono";
font-weight: 500;
font-size: 1rem;
margin: 2rem;
width: var(--content-width);
}
.content {
width: var(--content-width);
}

View file

@ -24,6 +24,11 @@
margin-top: 0;
}
.git-loading {
background: linear-gradient(90deg, rgba(248, 241, 241, 1) 0%, rgba(15, 11, 17, 0.31) 50%, rgba(248, 241, 241, 1) 100%);
background-size: 200% 100%;
}
.git-commit {
margin-left: auto;
border-radius: 1rem;

View file

@ -8,7 +8,10 @@
"description": "Informatics and electronics engineer",
"knowme": "Me Connaître"
},
"project":"Mes projets",
"project": {
"title": "Mes projets",
"description": "Mes projets principaux, scolaires ou personnels. J'essaie de faire en sorte qu'ils soient les plus aboutis possible."
},
"projects": [
{
"cover": "https://share.etheryo.fr/project/visual/wal_min.png",
@ -32,10 +35,17 @@
"topic": "videogame"
}
],
"lab": "Le laboratoire",
"lab": {
"title": "Le laboratoire",
"description": "Le laboratoire présente des mini-projets qui me servent à apprendre certaines logiques, langages, bibliothèques logicielles, et microcontrôleurs. Ceci est une simple galerie montrant mes trois derniers projets du moment. Rien de transcendant, simplement des idées/concepts."
},
"repos": [
"Training/yoyo_card",
"INSA/reoc",
"Training/rust_training"
]
],
"photo": {
"title": "Photographie",
"description": "Je ne suis pas un professionnel, mais il faut avouer que prendre des photos, faire du montage dessus, ou simplement régler la colorimétrie fait partie de mes passions. Cette petite galerie montre mes dernières photos, souvent liées à une émotion actuelle."
}
}

72
src/lib/ts/loading.ts Normal file
View file

@ -0,0 +1,72 @@
import anime from 'animejs';
export class LoadingSkeleton {
private _div: HTMLElement;
private _animation!: any;
constructor(div: HTMLElement) {
this._div = div;
}
public start(): void {
this._animation = anime({
targets: this._div,
backgroundPosition: [0, 200],
duration: 1500,
easing: 'linear',
loop: true,
});
}
public async stop(): Promise<void> {
this._animation?.pause();
const stopAnimation = anime({
targets: this._div,
opacity: [1, 0],
duration: 400,
easing: 'easeInOutQuad',
});
await stopAnimation.finished; // use `.finished` instead of `.promise`
}
}
export class Loading {
private _status: boolean;
private _promise: Promise<void>;
private _resolver: (() => void);
constructor() {
this._status = false;
this._resolver = (() => (null));
this._promise = new Promise<void>((resolve) => {
this._resolver = resolve;
});
}
public getStatus(): boolean {
return this._status;
}
public setStatus(value: boolean): boolean {
this._status = value;
if (value) this._resolver();
// Create a new promise when the status is set to false again
else {
this._promise = new Promise<void>((resolve) => {
this._resolver = resolve;
});
}
return this._status;
}
public getPromise(): Promise<void> {
if (this._status)
return Promise.resolve();
else {
return this._promise;
}
}
}

26
src/lib/ts/viewport.ts Normal file
View file

@ -0,0 +1,26 @@
let observer: IntersectionObserver;
function checkViewportObserver() {
if (observer) return;
// When scrolling so that intersection observer detects the viewport
observer = new IntersectionObserver(
(entries) => {
entries.forEach(entry => {
const eventName = entry.isIntersecting ? 'enterViewport' : 'exitViewport';
entry.target.dispatchEvent(new CustomEvent(eventName));
});
}
);
}
export default function viewport(element: HTMLElement) {
checkViewportObserver();
observer.observe(element);
return {
destroy() {
observer.unobserve(element);
}
}
}

View file

@ -40,7 +40,8 @@
</div>
</div>
<div class="section">
<h1>{hubjson.project}</h1>
<h1>{hubjson.project.title}</h1>
<p>{hubjson.project.description}</p>
</div>
<div class="flex w-100 justify-center">
<div class="content flex-row center">
@ -56,11 +57,16 @@
</div>
</div>
<div class="section">
<h1>{hubjson.lab}</h1>
<h1>{hubjson.lab.title}</h1>
<p>{hubjson.lab.description}</p>
</div>
<div class="flex w-100 justify-center">
{#each hubjson.repos as repo}
<Git {repo} />
{/each}
</div>
<div class="section">
<h1>{hubjson.photo.title}</h1>
<p>{hubjson.photo.description}</p>
</div>
</div>