Added Project element with its underlying topics. Reworked some elements on post-min and pill.

This commit is contained in:
Yohan Boujon 2025-04-02 22:49:18 +02:00
parent 3ac5290cbe
commit 03fdee90c9
13 changed files with 333 additions and 32 deletions

View file

@ -76,7 +76,7 @@
animateForeground(false, navbar_title);
}}
>
<div class="navbar-title content">
<div class="navbar-title navbar-content">
<h1 class="title">Etheryo</h1>
</div>
</div>
@ -94,7 +94,7 @@
animateForeground(false, navbar_category);
}}
>
<div class="content navbar-categories">
<div class="navbar-content navbar-categories">
<div>
<a class={isActive("/", pageUrl)} href="/">{mainjson.tab.hub}</a>
</div>

View file

@ -2,11 +2,13 @@
import "$lib/css/person.css";
import Button from "$lib/components/button.svelte";
import hubjson from "$lib/json/hub.json";
export let picture;
export let name = "John Doe";
export let pronouns = "";
export let description = "Normal human being I swear";
export let url = "https://github.com"
export let url = "https://github.com";
</script>
<div class="flex center">
@ -23,7 +25,12 @@
</div>
<p>{description}</p>
<div class="flex-row flex-end">
<Button label="Me connaître" action={() => {window.location.href = url;}} />
<Button
label={hubjson.person.knowme}
action={() => {
window.location.href = url;
}}
/>
</div>
</div>
</div>

View file

@ -8,7 +8,7 @@
import anime from "animejs";
export let cover =
"https://share.etheryo.fr/Rando-01.11.2023/Alix%20Mange%20Lac%20Rouge%20Bleu%20Orange%20Midi.jpg";
"https://share.etheryo.fr/rando/2024.07.28/IMG20240728142327.jpg";
export let title = "Title";
export let date = "01/01/1997";

View file

@ -0,0 +1,105 @@
<script>
import "$lib/css/base.css";
import "$lib/css/pill.css";
import "$lib/css/project.css";
import "$lib/css/post-min.css";
import topics from "$lib/ts/topic.ts";
import SvgIcon from "@jamescoyle/svelte-icon";
import { mdiChevronRight } from "@mdi/js";
import anime from "animejs";
export let cover =
"https://share.etheryo.fr/rando/2024.07.28/IMG20240728142327.jpg";
export let title = "Title";
export let description =
"This is a description, you can add some explaination to your project in here! It can always be interesting to talk about some subtext before going into the subject!";
export let topic = topics.embedded;
let post_div;
let chevron_div;
let title_h1;
let cursorX = 0;
let cursorY = 0;
let updateY = true;
function update_gradient(event, div) {
const rect = div.getBoundingClientRect();
if (updateY) {
cursorY = event.clientY - rect.top;
}
cursorX = event.clientX - rect.left;
post_div.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) {
const targetOpacity = isEntering ? 1 : 0;
anime({
targets: div_back,
opacity: [1 - targetOpacity, targetOpacity],
duration: 400,
easing: "easeInOutQuad",
});
}
function animateChevron(isEntering) {
let opacity = [0, 1];
let translateX = [-20, 0];
if (!isEntering) {
opacity.reverse();
translateX.reverse();
}
anime({
targets: chevron_div,
opacity: opacity,
translateX: translateX,
duration: 300,
easing: "easeOutQuad",
});
}
</script>
<div
role="button"
tabindex="0"
class="project-container"
on:mousemove={(event) => {
update_gradient(event, post_div);
}}
on:mouseenter={() => {
animateForeground(true, post_div);
animateChevron(true);
title_h1.style.textDecoration = "underline 2px";
}}
on:mouseleave={() => {
animateForeground(false, post_div);
animateChevron(false);
title_h1.style.textDecoration = "";
}}
>
<div class="project text-justify">
<img
alt="imgcool"
src={cover}
on:mouseenter={() => (updateY = false)}
on:mouseleave={() => (updateY = true)}
/>
<h1 bind:this={title_h1}>{title}</h1>
<p>{description}</p>
<div class="flex-row text-justify margin-bot-force">
<div class="pill project-pill">
<SvgIcon type="mdi" path={topic[1]}></SvgIcon>
<span>{topic[0]}</span>
</div>
<div class="flex-end project-next" bind:this={chevron_div}>
<SvgIcon type="mdi" path={mdiChevronRight} size={35}></SvgIcon>
</div>
</div>
</div>
<div class="post-min-overlay-front"></div>
<div class="post-min-overlay-back" bind:this={post_div}></div>
</div>

View file

@ -53,6 +53,8 @@ h2 {
--border-max: 2rem;
--profile-content-width-max: 40rem;
--profile-content-width-min: 36rem;
--content-width: 50rem;
--content-height: 50rem;
--width-min-desktop: 1275px;
--width-mobile: 875px;
@ -102,6 +104,10 @@ h2 {
margin: 2rem;
}
.content {
width: var(--content-width);
}
.flex-row {
display: flex;
align-items: center;
@ -125,6 +131,10 @@ h2 {
box-shadow: #41354340 0px 8px 18px -1px;
}
.w-100 {
width: 100%;
}
.h-100 {
height: 100%;
}
@ -180,6 +190,10 @@ h2 {
margin-left: 0.5rem;
}
.margin-bot-force {
margin-top: auto;
}
.padding-left-3 {
padding-left: 3rem;
}

View file

@ -57,7 +57,7 @@ a {
outline: var(--navbar-outline)
}
.content {
.navbar-content {
grid-area: overlay;
z-index: 1;
width: inherit;

View file

@ -3,7 +3,7 @@
}
.person-container {
width: 50rem;
width: 100%;
padding: 1rem;
}

View file

@ -21,16 +21,6 @@
margin-right: 1rem !important;
}
.pill svg {
border-radius: 100% !important;
width: 1.8rem !important;
height: 1.8rem !important;
padding: calc((3rem - 1.8rem)/2);
color: var(--color-background);
background: linear-gradient(180deg, rgb(52, 42, 58), rgb(38, 28, 44));
margin-right: 1rem;
}
.pill-profile {
transition: all .4s ease 0s;
}

View file

@ -90,12 +90,16 @@
margin-top: auto !important;
}
.post-min-pill span {
font-size: 0.8rem;
}
.post-min-pill svg {
border-radius: 100% !important;
width: 1.2rem !important;
height: 1.2rem !important;
padding: calc((2rem - 1.2rem)/2);
color: var(--color-background);
background: linear-gradient(180deg, rgb(52, 42, 58), rgb(38, 28, 44));
margin-right: 1rem;
}
.post-min-pill span {
font-size: 0.8rem;
}

127
src/lib/css/project.css Normal file
View file

@ -0,0 +1,127 @@
@media screen and (max-width: 1275px) {
.project-container {
height: calc(var(--content-height)/2);
width: calc((var(--content-width) + 6rem - 4rem)/3);
}
.project {
height: calc(var(--content-height)/2);
}
.project img {
height: calc(var(--content-height)/5);
width: calc(var(--content-width)/4);
}
}
@media screen and (min-width: 1276px) {
.project-container {
height: calc(var(--content-height)/2);
width: calc((var(--content-width) + 6rem - 4rem)/3);
}
.project {
height: calc(var(--content-height)/2);
}
.project img {
height: calc(var(--content-height)/5);
width: calc(var(--content-width)/4);
}
}
.project-container {
display: grid;
grid-template-areas:
"post-min-overlay-back"
"post-min-overlay-front"
"project";
margin-left: 1rem;
margin-right: 1rem;
}
.project {
cursor: pointer;
display: flex;
flex-direction: column;
grid-area: overlay;
z-index: var(--z-index-front);
}
.project img {
width: auto;
width: 100%;
object-fit: cover;
border-top-left-radius: 1rem;
border-top-right-radius: 1rem;
border-bottom-left-radius: 0.6rem;
border-bottom-right-radius: 0.6rem;
margin-bottom: 1rem;
}
.project h1 {
font-family: 'JetBrains Mono';
font-weight: 800;
font-size: 1.1rem;
margin-left: 1rem;
margin-right: 1rem;
margin-bottom: 0;
user-select: none;
/* Overflow */
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
text-overflow: ellipsis;
-webkit-line-clamp: 2;
line-clamp: 2;
}
.project p {
font-family: 'JetBrains Mono';
font-weight: 400;
font-style: italic;
font-size: 0.9rem;
margin-left: 1rem;
margin-right: 1rem;
/* Overflow */
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
text-overflow: ellipsis;
-webkit-line-clamp: 4;
line-clamp: 4;
}
.project span {
font-family: 'JetBrains Mono';
color: var(--color-background);
margin: 0.7rem;
padding: 0;
}
.project-pill {
background-color: var(--color-text);
margin-bottom: 0.5rem;
width: fit-content;
margin-bottom: 1rem;
}
.project-pill svg {
border-radius: 100% !important;
padding: calc((2rem - 1.2rem)/2);
padding-right: 0;
color: var(--color-background);
}
.project-next {
opacity: 0;
}
.project-next svg {
color: var(--color-text);
margin-right: 0.5rem;
}

View file

@ -5,7 +5,28 @@
"person": {
"name": "Yohan Boujon",
"pronouns": "il/lui",
"description": "Informatics and electronics engineer"
"description": "Informatics and electronics engineer",
"knowme": "Me Connaître"
},
"projects":"Mes projets"
"project":"Mes projets",
"projects": [
{
"cover": "https://share.etheryo.fr/INSA/wal/wal.png",
"title": "What A Leak!",
"description": "Water leak detection project with INSA Toulouse in 5th year.",
"topic": "embedded"
},
{
"cover": "https://share.etheryo.fr/projects/shared-memory/config.png",
"title": "Shared memory cache on multiple kernels",
"description": "Using NFS, programmed a kernel driver that can read/write data onto a shared ram.",
"topic": "kernel"
},
{
"cover": "https://share.etheryo.fr/projects/yoyo_tetris/yoyotetris.png",
"title": "yoyoTetris",
"description": "A simple game in C++ using Raylib.",
"topic": "videogame"
}
]
}

13
src/lib/ts/topic.ts Normal file
View file

@ -0,0 +1,13 @@
import { mdiMemory, mdiPenguin, mdiGamepadVariant } from "@mdi/js";
type TopicKey = "embedded" | "kernel" | "videogame";
type Topic = [string, string];
const topics: Record<TopicKey, Topic> = {
embedded: ["Embedded", mdiMemory],
kernel: ["Kernel Dev", mdiPenguin],
videogame: ["Video Game", mdiGamepadVariant],
};
export default topics;

View file

@ -4,6 +4,10 @@
import CoverImg from "$lib/components/cover-img.svelte";
import Person from "$lib/components/person.svelte";
import Project from "$lib/components/project.svelte";
import topics from "$lib/ts/topic.ts";
import hubjson from "$lib/json/hub.json";
let hub_cover =
@ -23,6 +27,8 @@
<div class="section">
<h1>{hubjson.who}</h1>
</div>
<div class="flex w-100 justify-center">
<div class="content">
<Person
picture={profile_pic}
name={hubjson.person.name}
@ -30,7 +36,21 @@
description={hubjson.person.description}
url="/about"
/>
</div>
</div>
<div class="section">
<h1>{hubjson.projects}</h1>
<h1>{hubjson.project}</h1>
</div>
<div class="flex w-100 justify-center">
<div class="content flex-row center">
{#each hubjson.projects as project, index}
<Project
cover={hubjson.projects[index].cover}
title={hubjson.projects[index].title}
description={hubjson.projects[index].description}
topic={topics[hubjson.projects[index].topic]}
/>
{/each}
</div>
</div>
</div>