Added components from 'blog'.

This commit is contained in:
Yohan Boujon 2025-03-28 20:51:14 +01:00
parent 6f39c30d4d
commit 78af91262b
36 changed files with 2504 additions and 2 deletions

View file

@ -0,0 +1,132 @@
<script>
import '$lib/css/base.css';
import '$lib/css/archive.css';
import SvgIcon from '@jamescoyle/svelte-icon';
import { mdiChevronRight } from '@mdi/js';
import anime from 'animejs';
export let fontPost = 1;
export let paddingPost = 0.5;
export let customStyle = "";
const posts = {
'Août 2024': [
'Est-ce que le lorem est Ipsum ?',
"J'aime bien le jeu Minecraft",
'Comment Installer Linus Torvalds sur sa tablette',
'Pourquoi "Le miam" pourrait être votre groupe de musique préféré ?',
"Peut-on vivre dans une maison en pain d'épices ?"
],
'Juillet 2024': [
'Les secrets du café qui ne refroidit jamais',
'Comment devenir un ninja en 10 leçons faciles',
'La vérité derrière les licornes: Mythe ou réalité ?',
"J'ai adopté un dragon, voici ce qui s'est passé"
],
'Juin 2024': [
'Pourquoi "Le miam" pourrait être votre groupe de musique préféré ?',
'La recette secrète de la pizza à la glace',
'Comment devenir un expert en pirouettes en 5 jours'
],
'Mai 2024': [
'Mon voyage au centre de la Terre en montgolfière',
'Pourquoi les pandas devraient être vos nouveaux colocataires',
'Les chats dominent-ils vraiment Internet ?'
]
};
const size = Object.keys(posts).length;
let archiveRefs = Array(size);
let archivePostRefs = Array(size);
let isActive = Array(size).fill(false);
let indexArchive = -1;
function toggleArchive(date, index) {
const archive = archiveRefs[index];
const archivePost = archivePostRefs[index];
const svg = archiveRefs[index].children[1];
const rvalue = isActive[index] ? [90, 0] : [0, 90];
const ovalue = isActive[index] ? [1, 0] : [0, 1];
const shadow = isActive[index] ? '' : '0px 8px 18px -1px rgba(52, 42, 58, 0.2)';
const mbvalue = isActive[index] ? [0.5, 0] : [0, 0.5];
const hvalue = isActive[index]
? [posts[date].length * (2 * paddingPost + fontPost + 0.5), 0]
: [0, posts[date].length * (2 * paddingPost + fontPost + 0.5)];
isActive[index] = isActive[index] ? false : true;
if (!isActive[index]) {
indexArchive = -1;
archivePost.style.opacity = '0';
} else {
indexArchive = index;
archivePost.style.display = 'block';
}
anime({
targets: { transform: rvalue[0], opacity: ovalue[0], margin: mbvalue[0], height: hvalue[0] },
transform: rvalue,
opacity: ovalue,
margin: mbvalue,
height: hvalue,
duration: 300,
easing: 'easeInOutQuad',
update: function (anim) {
svg.style.transform = `rotate(${anim.animations[0].currentValue}deg)`;
archive.style.background = `linear-gradient(90deg, rgba(65,53,67,${anim.animations[1].currentValue}) 0%, rgba(38,28,44,${anim.animations[1].currentValue}) 100%)`;
archive.style.boxShadow = shadow;
archive.style.marginBottom = `${anim.animations[2].currentValue}rem`;
archivePost.style.height = `${anim.animations[3].currentValue}rem`;
},
complete: function () {
if (!isActive[index]) {
archivePost.style.display = 'none';
return;
}
anime({
targets: archivePost,
opacity: ovalue,
duration: 300,
easing: 'easeOutQuad'
});
}
});
anime({
targets: archive,
color: isActive[index] ? '#F8F1F1' : '#261C2C',
duration: 200,
easing: 'easeInOutQuad'
});
}
</script>
<div
class="archive-container {customStyle}"
style="--font-post: {fontPost}rem; --padding-post: {paddingPost}rem;"
>
<!-- svelte-ignore a11y-no-static-element-interactions -->
{#each Object.keys(posts) as date, index}
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div
bind:this={archiveRefs[index]}
class="archive"
on:click={() => {
if (indexArchive != -1 && indexArchive != index) {
toggleArchive(date, indexArchive);
}
toggleArchive(date, index);
}}
>
<span>{date}</span>
<SvgIcon type="mdi" path={mdiChevronRight}></SvgIcon>
</div>
<div bind:this={archivePostRefs[index]} class="archive-post">
{#each posts[date] as p}
<div>
<span>{p}</span>
</div>
{/each}
</div>
{/each}
</div>

View file

@ -0,0 +1,26 @@
<script>
import '$lib/css/base.css';
import '$lib/css/button-slider.css';
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher();
export let keys = ['Button1', 'Button2'];
export let active = 0;
export let width = "100%";
function changeActive(id) {
dispatch('click', { id: id });
active = id;
}
</script>
<div class="button-slider-container center" style="--button-slider-width: {width}">
{#each keys as k, id}
<button
class={id === active ? 'button-slider-active' : ''}
on:click={() => {
changeActive(id);
}}><span>{k}</span></button
>
{/each}
</div>

View file

@ -0,0 +1,78 @@
<script>
import '$lib/css/base.css';
import '$lib/css/carousel.css';
import SvgIcon from '@jamescoyle/svelte-icon';
import { mdiAccount, mdiCalendarRange } from '@mdi/js';
export let posts;
const mainpost = posts[0];
let movable;
function redirectTo(url) {
window.location.href = url;
}
function handleKeyDown(event, url) {
console.log(event);
if (event.key === 'Enter' || event.key === ' ') {
redirectTo(url);
}
}
</script>
<div class="carousel-v-main">
<div
class="carousel-v-bigpost"
role="button"
tabindex="0"
on:click={() => {
redirectTo(`/articles/${mainpost.slug}`);
}}
on:keydown={(event) => handleKeyDown(event, `/articles/${mainpost.slug}`)}
>
<div>
<h2>{mainpost.title}</h2>
<div class="center flex justify-center h-70 margin-bottom ">
<img class="carousel-picture" alt="mainpicture" src={mainpost.picture} />
</div>
<div class="flex align-center margin-horizontal-05">
<SvgIcon type="mdi" path={mdiCalendarRange} size="26" />
{mainpost.date}
</div>
<div class="flex align-center margin-horizontal-05">
<SvgIcon type="mdi" path={mdiAccount} size="26" />
{mainpost.author}
</div>
</div>
</div>
<div class="carousel-v-minpost-container">
<div bind:this={movable}>
{#each posts as p, index}
{#if index > 0}
<div
class="carousel-v-minpost"
role="button"
tabindex="0"
on:click={() => {
redirectTo(`/articles/${p.slug}`);
}}
on:keydown={(event) => handleKeyDown(event, `/articles/${p.slug}`)}
>
<img class="carousel-picture" alt="mainpicture" src={p.picture} />
<div class="flex-col align justify-center">
<h2>{p.title}</h2>
<div class="flex align-center margin-horizontal-05">
<SvgIcon type="mdi" path={mdiCalendarRange} size="26" />
{p.date}
</div>
<div class="flex align-center margin-horizontal-05">
<SvgIcon type="mdi" path={mdiAccount} size="26" />
{p.author}
</div>
</div>
</div>
{/if}
{/each}
</div>
</div>
</div>

View file

@ -0,0 +1,30 @@
<script>
import { onMount } from 'svelte';
import anime from 'animejs';
import '$lib/css/base.css';
import '$lib/css/count.css';
export let name = 'Articles';
export let num = 69;
let count_num = 0;
onMount(async () => {
anime({
targets: { count: 0 },
count: [0, num],
delay: 500,
duration: 1500,
easing: 'easeOutQuint',
update: function (anim) {
count_num = Math.floor(anim.animations[0].currentValue);
}
});
});
</script>
<div class="count center">
<h1>{count_num}</h1>
<h2>{name}</h2>
</div>

View file

@ -0,0 +1,58 @@
<script>
import '$lib/css/base.css';
import '$lib/css/footer.css';
import Page1 from '$lib/components/footer/page1.svelte';
import Page2 from '$lib/components/footer/page2.svelte';
import Page3 from '$lib/components/footer/page3.svelte';
import ButtonSlider from '$lib/components/button-slider.svelte';
import anime from 'animejs';
let active = 0;
let page = [Page1, Page2, Page3];
let pageDiv;
function slideText(event) {
const id = event.detail.id;
const width = window.innerWidth/2;
const animTranslate = active > id ? [width, -width] : [-width, width];
anime({
targets: pageDiv,
translateX: animTranslate[0],
opacity: 0,
duration: 300,
easing: 'easeInQuad',
complete: function () {
active = id;
pageDiv.style.transform = `translateX(${animTranslate[1]}px)`;
anime({
targets: pageDiv,
translateX: 0,
opacity: 1,
duration: 300,
easing: 'easeOutQuad'
});
}
});
}
</script>
<div class="footer-container">
<div class="footer-content">
<div class="footer-left">
<h1 class="title">Etheryo</h1>
</div>
<div class="footer-right">
<div class="footer-page justify-center" bind:this={pageDiv}>
<svelte:component this={page[active]} />
</div>
</div>
</div>
<div class="footer-slider align-center">
<span>{new Date().getFullYear()} • Tous droits réservés • Yohan Boujon</span>
<div class="flex-end">
<ButtonSlider keys={['À propos', 'Notre Vision', 'Contacter']} on:click={slideText} />
</div>
</div>
</div>

View file

@ -0,0 +1,24 @@
<script>
import '$lib/css/footer/page.css';
import SvgIcon from '@jamescoyle/svelte-icon';
import { mdiFormatQuoteClose, mdiFormatQuoteOpen } from '@mdi/js';
</script>
<div class="page-icon-text">
<img alt="github" src="https://cdn.simpleicons.org/github/F8F1F1" />
<a target="_blank" href="https://github.com/yoboujon/etheryo-blog">Code source</a>
</div>
<div class="page-icon-text">
<img alt="raspberrypi" src="https://cdn.simpleicons.org/raspberrypi/F8F1F1" />
<a target="_blank" href="https://fr.wikipedia.org/wiki/Raspberry_Pi">Hébergé sur Raspberry Pi</a>
</div>
<div class="page-icon-text">
<img alt="crowcpp" src="https://crowcpp.org/master/assets/favicon.svg" />
<a target="_blank" href="https://github.com/CrowCpp/Crow">Réalisé avec CrowCpp</a>
</div>
<div class="page-icon-text page-special">
<SvgIcon type="mdi" path={mdiFormatQuoteOpen} />
<span><i>Keep the web free</i></span>
<SvgIcon type="mdi" path={mdiFormatQuoteClose} />
</div>

View file

@ -0,0 +1,19 @@
<script>
import '$lib/css/base.css';
import '$lib/css/footer/page.css';
import SvgIcon from '@jamescoyle/svelte-icon';
import { mdiEye } from '@mdi/js';
</script>
<div class="page-icon-text">
<SvgIcon type="mdi" path={mdiEye} />
<h1>Notre Vision</h1>
</div>
<div class="page-text">
<span class="page-overflow text-justify"
>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras lectus ante, porttitor eget massa
sit amet, volutpat cursus mauris. Proin et massa dui. Vestibulum eu tempus nisl, vitae bibendum
urna. Sed tincidunt est non nulla scelerisque.
</span>
</div>

View file

@ -0,0 +1,16 @@
<script>
import '$lib/css/base.css';
import '$lib/css/footer/page.css';
import SvgIcon from '@jamescoyle/svelte-icon';
import { mdiEmailFast, mdiHelp } from '@mdi/js';
</script>
<div class="page-icon-text">
<SvgIcon type="mdi" path={mdiEmailFast} />
<a href="mailto:blog@etheryo.fr">Envoyez nous un mail</a>
</div>
<div class="page-icon-text">
<SvgIcon type="mdi" path={mdiHelp} />
<a href="https://duckduckgo.com/">Besoin d'aide</a>
</div>

View file

@ -0,0 +1,73 @@
<script>
import '$lib/css/base.css';
import '$lib/css/link.css';
import { hexTorgb, darkenHexTorgb } from '$lib/ts/color.ts';
import SvgIcon from '$lib/components/svg-icon-custom.svelte';
import { mdiChevronRight } from '@mdi/js';
import anime from 'animejs';
let color = '9A031E';
const color_rgb = hexTorgb(color);
const color_darken = darkenHexTorgb(color, 0.8);
let imgBase = 'placeholder_link.png';
let imgHover = 'placeholder_link_hover.png';
let base;
let hover;
let span_link;
let svg_icon;
let div_background;
let span_width = '0%';
async function enter() {
span_width = '100%';
span_link.style.color = 'var(--color-background)';
svg_icon.svgElement.style.color = 'var(--color-background)';
svg_icon.svgElement.style.transform = 'translateX(8px)';
updatePicture(false, base);
updatePicture(true, hover);
updatePicture(true, div_background);
}
async function leave() {
span_width = '0%';
span_link.style.color = 'var(--color-text)';
svg_icon.svgElement.style.color = 'var(--color-text)';
svg_icon.svgElement.style.transform = '';
updatePicture(true, base);
updatePicture(false, hover);
updatePicture(false, div_background);
}
function updatePicture(show, img) {
const targetOpacity = show ? 1 : 0;
anime({
targets: img,
opacity: [1 - targetOpacity, targetOpacity],
duration: 400,
easing: 'easeInOutQuad'
});
}
</script>
<div
style="--shadow: rgba({color_rgb.r}, {color_rgb.g}, {color_rgb.b}, 0.4) 0px 30px 60px -12px, rgba({color_darken.r}, {color_darken.g}, {color_darken.b}, 0.3) 0px 18px 36px -18px; --gradient: linear-gradient(180deg, #{color} 0%, rgba({color_darken.r},{color_darken.g}, {color_darken.b}, 1) 100%); --span-width: {span_width};"
class="link-container"
on:mouseenter={enter}
on:mouseleave={leave}
role="button"
tabindex="0"
>
<div class="link-background" bind:this={div_background}>
</div>
<div class="link-content flex-row center">
<div class="link-img">
<img bind:this={base} alt="base" src={imgBase} />
<img bind:this={hover} alt="hover" class="link-img-hover" src={imgHover} />
</div>
<span bind:this={span_link}>Link</span>
<SvgIcon type="mdi" path={mdiChevronRight} size={80} bind:this={svg_icon}></SvgIcon>
</div>
</div>

View file

@ -0,0 +1,111 @@
<!-- svelte-ignore a11y-missing-content -->
<script>
import '$lib/css/base.css';
import '$lib/css/navbar.css';
import { page } from '$app/stores';
import anime from 'animejs';
import Search from '$lib/components/search.svelte';
const SCROLL = 150;
$: pageUrl = $page.url.pathname;
let scrollY=0;
let cursorX;
let cursorY;
let navbar_title;
let navbar_category;
function isActive(str, url) {
if (url === str) return 'navbar-active';
else return '';
}
function isActiveMultiple(strArray, url) {
for (const str of strArray) {
const returnVal = isActive(str, url);
if (returnVal != '') return returnVal;
}
return '';
}
function update_gradient(event, div) {
const rect = div.getBoundingClientRect();
cursorX = event.clientX - rect.left;
cursorY = event.clientY - rect.top;
div.style.backgroundImage = `radial-gradient(circle farthest-corner at ${Math.floor(cursorX)}px ${Math.floor(cursorY)}px, var(--navbar-ligher) 0%, var(--navbar-darker) 100%)`;
}
function animateForeground(isEntering, div_back) {
const targetOpacity = isEntering ? 1 : 0;
anime({
targets: div_back,
opacity: [1 - targetOpacity, targetOpacity],
duration: 400,
easing: 'easeInOutQuad'
});
}
function changeScroll() {
document.documentElement.style.setProperty(
'--navbar-height',
scrollY < SCROLL ? '6rem' : '5rem'
);
}
</script>
<svelte:window bind:scrollY on:scroll={changeScroll} />
<!-- Navbar -->
<nav class={scrollY < SCROLL ? 'flex-row' : 'flex-row floating'}>
<div
role="banner"
class="{scrollY < SCROLL ? 'disabled' : 'navbar-height flex-row container'}"
on:mousemove={(event) => {
update_gradient(event, navbar_title);
}}
on:mouseenter={() => {
animateForeground(true, navbar_title);
}}
on:mouseleave={() => {
animateForeground(false, navbar_title);
}}
>
<div class="navbar-title content">
<h1 class="title">Etheryo</h1>
</div>
</div>
<div
role="banner"
class="navbar-height flex-row flex-end container"
on:mousemove={(event) => {
update_gradient(event, navbar_category);
}}
on:mouseenter={() => {
animateForeground(true, navbar_category);
}}
on:mouseleave={() => {
animateForeground(false, navbar_category);
}}
>
<div class="content navbar-categories">
<div>
<a class={isActiveMultiple(['/', '/articles', '/style'], pageUrl)} href="/articles"
>Articles</a
>
</div>
<div>
<a class={isActive('/authors', pageUrl)} href="/authors">Auteurs</a>
</div>
<div>
<a class={isActive('/categories', pageUrl)} href="/categories">Catégories</a>
</div>
<Search width="15rem" font_size="0.8rem" padding="0rem" logo_size="25" />
</div>
<div class={scrollY < SCROLL ? 'navbar-overlay-front' : ''} />
<div class={scrollY < SCROLL ? 'navbar-overlay-back' : ''} bind:this={navbar_category} />
</div>
</nav>

View file

@ -0,0 +1,73 @@
<script>
import '$lib/css/base.css';
import '$lib/css/pill.css';
import '$lib/css/post-min.css';
import SvgIcon from '@jamescoyle/svelte-icon';
import { mdiCalendarRange } from '@mdi/js';
import anime from 'animejs';
export let cover =
'https://share.etheryo.fr/Rando-01.11.2023/Alix%20Mange%20Lac%20Rouge%20Bleu%20Orange%20Midi.jpg';
export let title = 'Title';
export let date = '01/01/1997';
let post_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'
});
}
</script>
<div
role="button"
tabindex="0"
class="post-min-container"
on:mousemove={(event) => {
update_gradient(event, post_div);
}}
on:mouseenter={() => {
animateForeground(true, post_div);
title_h1.style.textDecoration = 'underline 2px';
}}
on:mouseleave={() => {
animateForeground(false, post_div);
title_h1.style.textDecoration = '';
}}
>
<div class="post-min">
<img
alt="imgcool"
src={cover}
on:mouseenter={() => (updateY = false)}
on:mouseleave={() => (updateY = true)}
/>
<h1 bind:this={title_h1}>{title}</h1>
<div class="pill post-min-pill post-min-end">
<SvgIcon type="mdi" path={mdiCalendarRange} size="120"></SvgIcon>
<span>{date}</span>
</div>
</div>
<div class="post-min-overlay-front" />
<div class="post-min-overlay-back" bind:this={post_div} />
</div>

View file

@ -0,0 +1,85 @@
<script>
import '$lib/css/base.css';
import '$lib/css/pill.css';
import '$lib/css/post.css';
import SvgIcon from '@jamescoyle/svelte-icon';
import { mdiCalendarRange } from '@mdi/js';
import anime from 'animejs';
export let cover =
'https://share.etheryo.fr/Rando-01.11.2023/Alix%20Mange%20Lac%20Rouge%20Bleu%20Orange%20Midi.jpg';
export let title = 'Title';
export let text = 'Little description.';
export let author = 'Author';
export let date = '01/01/1997';
export let profile = 'https://i.pravatar.cc/300';
let post_div;
let title_h1;
let cursorX = 0;
let cursorY = 0;
let updateX = true;
function update_gradient(event, div) {
const rect = div.getBoundingClientRect();
if (updateX) {
cursorX = event.clientX - rect.left;
}
cursorY = event.clientY - rect.top;
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'
});
}
</script>
<!-- svelte-ignore a11y-no-static-element-interactions -->
<div
class="post-container"
on:mousemove={(event) => {
update_gradient(event, post_div);
}}
on:mouseenter={() => {
animateForeground(true, post_div);
title_h1.style.textDecoration = 'underline 3px';
}}
on:mouseleave={() => {
animateForeground(false, post_div);
title_h1.style.textDecoration = '';
}}
>
<div class="post">
<img
alt="imgcool"
src={cover}
on:mouseenter={() => (updateX = false)}
on:mouseleave={() => (updateX = true)}
/>
<div class="post-text">
<div>
<h1 bind:this={title_h1}>{title}</h1>
<p>{text}</p>
</div>
<div class="text-container">
<div class="pill pill-profile post-author-pill">
<img alt="profile" src={profile} />
<span>{author}</span>
</div>
<div class="pill pill-reversed flex-end">
<span>{date}</span>
<SvgIcon type="mdi" path={mdiCalendarRange} size="120"></SvgIcon>
</div>
</div>
</div>
</div>
<div class="post-overlay-front" />
<div class="post-overlay-back" bind:this={post_div} />
</div>

View file

@ -0,0 +1,108 @@
<script>
import '$lib/css/base.css';
import '$lib/css/search.css';
import SvgIcon from '$lib/components/svg-icon-custom.svelte';
import { mdiMagnify } from '@mdi/js';
import anime from 'animejs';
export let width = '50%';
export let font_size = '1rem';
export let padding = '1rem';
export let logo_size = 20;
export let margin = '0rem';
export let text_color = 'var(--color-subtext)';
let div_search;
let input_search;
let svgIcon;
let search_box;
let selected = false;
function animate() {
// Animating the Svg Icon
if (selected) {
return;
}
selected = true;
showSearch(true);
// Animating the div
const max = div_search.getBoundingClientRect().right - div_search.getBoundingClientRect().left;
anime({
targets: { position_var: 0 },
position_var: [0, max],
easing: 'linear',
duration: 300,
update: function (anim) {
div_search.style.background = `radial-gradient(circle farthest-corner at ${anim.animations[0].currentValue}px 0px, #958a98 0%, var(--color-background) 100%)`;
},
complete: function () {
anime({
targets: { percent_var: 0, opacity_var: 1 },
percent_var: [0, 100],
opacity_var: [1, 0],
easing: 'easeOutQuad',
duration: 300,
update: function (anim) {
div_search.style.background = `radial-gradient(circle farthest-corner at 0px 0px, var(--color-background) ${anim.animations[0].currentValue}%, rgba(149,138,152,${anim.animations[1].currentValue}) 100%)`;
}
});
}
});
}
function closeSearch(event) {
if (selected && event.target != input_search && event.target != svgIcon.svgElement) {
showSearch(false);
selected = false;
}
}
function showSearch(isEntering) {
//transform: ;
if (isEntering) {
search_box.style.display = 'block';
}
const ovalue = isEntering ? [0, 1] : [1, 0];
anime({
targets: { opacity: 0 },
opacity: ovalue,
duration: 200,
easing: 'easeInOutQuad',
update: function (anim) {
search_box.style.opacity = `${anim.animations[0].currentValue}`;
search_box.style.transform = `translateX(-1rem) translateY(${anim.animations[0].currentValue}rem)`;
},
complete: function () {
if (!isEntering) {
search_box.style.display = 'none';
}
}
});
}
</script>
<svelte:window on:click={closeSearch} />
<!-- svelte-ignore a11y-click-events-have-key-events -->
<!-- svelte-ignore a11y-no-static-element-interactions -->
<div style="width: {width}; margin: {margin} !important;">
<div class="search" on:click={animate} bind:this={div_search}>
<SvgIcon
type="mdi"
path={mdiMagnify}
size={logo_size}
bind:this={svgIcon}
padding={logo_size / 3}
></SvgIcon>
<input
type="text"
style="font-size: {font_size};padding-top: {padding};padding-bottom: {padding};color: {text_color};"
placeholder="Rechercher..."
bind:this={input_search}
/>
</div>
<div class="search-box" bind:this={search_box}></div>
</div>

View file

@ -0,0 +1,128 @@
<script>
import '$lib/css/base.css';
import '$lib/css/social.css';
import anime from 'animejs';
import SvgIcon from '@jamescoyle/svelte-icon';
let social_list = [
{
pic: 'https://cdn.simpleicons.org/instagram',
color: 'E4405F',
alt: 'Instagram',
name: '@yo.boujon',
link: 'https://www.instagram.com/yoboujon/'
},
{
pic: 'https://cdn.simpleicons.org/github',
color: '181717',
alt: 'Github',
name: 'yoboujon',
link: 'https://github.com/yoboujon'
},
{
pic: 'https://cdn.simpleicons.org/youtube',
color: 'FF0000',
alt: 'Youtube',
name: '@yoboujon',
link: 'https://www.youtube.com/@yoboujon'
},
{
pic: 'https://img.icons8.com/?size=200&id=8808&format=png&color=0A66C2',
color: '0A66C2',
alt: 'Linkedin',
name: 'Yohan Boujon',
link: 'https://www.linkedin.com/in/yohan-boujon-a08511202/'
},
{
icon: 'M10.59,13.41C11,13.8 11,14.44 10.59,14.83C10.2,15.22 9.56,15.22 9.17,14.83C7.22,12.88 7.22,9.71 9.17,7.76V7.76L12.71,4.22C14.66,2.27 17.83,2.27 19.78,4.22C21.73,6.17 21.73,9.34 19.78,11.29L18.29,12.78C18.3,11.96 18.17,11.14 17.89,10.36L18.36,9.88C19.54,8.71 19.54,6.81 18.36,5.64C17.19,4.46 15.29,4.46 14.12,5.64L10.59,9.17C9.41,10.34 9.41,12.24 10.59,13.41M13.41,9.17C13.8,8.78 14.44,8.78 14.83,9.17C16.78,11.12 16.78,14.29 14.83,16.24V16.24L11.29,19.78C9.34,21.73 6.17,21.73 4.22,19.78C2.27,17.83 2.27,14.66 4.22,12.71L5.71,11.22C5.7,12.04 5.83,12.86 6.11,13.65L5.64,14.12C4.46,15.29 4.46,17.19 5.64,18.36C6.81,19.54 8.71,19.54 9.88,18.36L13.41,14.83C14.59,13.66 14.59,11.76 13.41,10.59C13,10.2 13,9.56 13.41,9.17Z',
color: 'AD62AA',
alt: 'Etheryo',
name: 'Etheryo',
link: 'https://www.etheryo.fr'
},
{
icon: 'M10.59,13.41C11,13.8 11,14.44 10.59,14.83C10.2,15.22 9.56,15.22 9.17,14.83C7.22,12.88 7.22,9.71 9.17,7.76V7.76L12.71,4.22C14.66,2.27 17.83,2.27 19.78,4.22C21.73,6.17 21.73,9.34 19.78,11.29L18.29,12.78C18.3,11.96 18.17,11.14 17.89,10.36L18.36,9.88C19.54,8.71 19.54,6.81 18.36,5.64C17.19,4.46 15.29,4.46 14.12,5.64L10.59,9.17C9.41,10.34 9.41,12.24 10.59,13.41M13.41,9.17C13.8,8.78 14.44,8.78 14.83,9.17C16.78,11.12 16.78,14.29 14.83,16.24V16.24L11.29,19.78C9.34,21.73 6.17,21.73 4.22,19.78C2.27,17.83 2.27,14.66 4.22,12.71L5.71,11.22C5.7,12.04 5.83,12.86 6.11,13.65L5.64,14.12C4.46,15.29 4.46,17.19 5.64,18.36C6.81,19.54 8.71,19.54 9.88,18.36L13.41,14.83C14.59,13.66 14.59,11.76 13.41,10.59C13,10.2 13,9.56 13.41,9.17Z',
color: 'AD62AA',
alt: 'Saoul Bonmonsieur',
name: 'Saoul Bonmonsieur',
link: 'https://saoulbonmonsieur.etheryo.fr/'
}
];
let div_social;
const resetcolor = {
r: 15,
g: 11,
b: 17,
a: 0.1
};
let oldcolor = resetcolor;
function changeBackground(color, reset) {
let newcolor = resetcolor;
if (!reset) {
newcolor = {
r: parseInt(color.substring(0, 2), 16),
g: parseInt(color.substring(2, 4), 16),
b: parseInt(color.substring(4, 6), 16),
a: 0.2
};
}
anime({
targets: { red: oldcolor.r, green: oldcolor.g, blue: oldcolor.b, alpha: oldcolor.a },
red: [oldcolor.r, newcolor.r],
green: [oldcolor.g, newcolor.g],
blue: [oldcolor.b, newcolor.b],
alpha: [oldcolor.a, newcolor.a],
duration: 500,
easing: 'easeInOutQuad',
update: function (anim) {
div_social.style.backgroundImage = `linear-gradient(180deg, rgba(248, 241, 241, 1) 0%, rgba(${anim.animations[0].currentValue},${anim.animations[1].currentValue},${anim.animations[2].currentValue},${anim.animations[3].currentValue}) 100%)`;
oldcolor = {
r: anim.animations[0].currentValue,
g: anim.animations[1].currentValue,
b: anim.animations[2].currentValue,
a: anim.animations[3].currentValue
};
}
});
}
function openWindow(url) {
window.open(url, '_blank');
}
</script>
<div class="social social-width" bind:this={div_social}>
<h1>Liens</h1>
{#each social_list as s}
<div
class="social-link align-center"
style="--social-color: #{s.color};"
role="button"
tabindex="0"
title={s.alt}
on:keypress={() => {
openWindow(s.link);
}}
on:click={() => {
openWindow(s.link);
}}
on:mouseenter={() => {
changeBackground(s.color, false);
}}
on:mouseleave={() => {
changeBackground(s.color, true);
}}
>
{#if s.pic === undefined}
<SvgIcon size="32" type="mdi" path={s.icon}></SvgIcon>
{:else}
<img alt={s.alt} src={s.pic} />
{/if}
<span>{s.name}</span>
</div>
{/each}
</div>

View file

@ -0,0 +1,57 @@
<svelte:options accessors={true} />
<script>
const types = {
mdi: {
size: 24,
viewbox: '0 0 24 24'
},
'simple-icons': {
size: 24,
viewbox: '0 0 24 24'
},
default: {
size: 0,
viewbox: '0 0 0 0'
}
};
export let type = null;
export let path;
export let size = null;
export let viewbox = null;
export let flip = 'none';
export let rotate = 0;
export let padding = 0;
// Reactive statements to set default values based on type
$: defaults = types[type] || types.default;
$: sizeValue = size || defaults.size;
$: viewboxValue = viewbox || defaults.viewbox;
$: sx = ['both', 'horizontal'].includes(flip) ? '-1' : '1';
$: sy = ['both', 'vertical'].includes(flip) ? '-1' : '1';
$: r = isNaN(rotate) ? rotate : rotate + 'deg';
export let svgElement; // To expose the reference
</script>
<svg
bind:this={svgElement}
width={sizeValue}
height=auto
viewBox={viewboxValue}
style="--sx: {sx}; --sy: {sy}; --r: {r}; padding: {padding}px"
{...$$restProps}
>
<path d={path} />
</svg>
<style>
svg {
transform: rotate(var(--r, 0deg)) scale(var(--sx, 1), var(--sy, 1));
}
path {
fill: currentColor;
}
</style>

51
src/lib/css/archive.css Normal file
View file

@ -0,0 +1,51 @@
.archive-container {
border-radius: 1rem;
color: var(--color-text);
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;
}
.archive {
font-family: 'JetBrains Mono';
font-size: 1.2rem;
padding: 1rem;
display: flex;
flex-direction: row;
justify-content: space-between;
cursor: pointer;
border-radius: 1rem;
}
.archive-post {
font-family: 'JetBrains Mono';
font-size: var(--font-post);
padding-left: 1rem;
color: var(--color-subtext);
opacity: 0;
height: 0px;
display: none;
}
.archive-post > div {
width: auto;
}
.archive-post span {
/* Overflow */
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
text-overflow: ellipsis;
-webkit-line-clamp: 1;
line-clamp: 1;
}
.archive-post span:hover {
color: var(--palette-pink);
text-decoration: underline 2px;
cursor: pointer;
}
.archive-post div {
padding: var(--padding-post);
}

29
src/lib/css/article.css Normal file
View file

@ -0,0 +1,29 @@
:root {
--banner-height: 60vh;
}
.article-banner {
display: grid;
grid-template-areas:
"article-banner-gradient"
"article-banner-content";
height: var(--banner-height);
width: 100dvw;
}
.article-banner-background {
grid-area: overlay;
width: 100dvw;
height: var(--banner-height);
z-index: var(--z-index-last);
background-image: linear-gradient(to right, var(--navbar-dark) 0%, var(--navbar-light) 100%);
border-bottom-left-radius: 2rem;
border-bottom-right-radius: 2rem;
box-shadow: rgba(79, 50, 93, 0.25) 0px 30px 60px -12px, rgba(0, 0, 0, 0.3) 0px 18px 36px -18px;
}
.article-banner-content {
grid-area: overlay;
width: 100dvw;
height: var(--banner-height);
}

183
src/lib/css/base.css Normal file
View file

@ -0,0 +1,183 @@
@import url('https://fonts.googleapis.com/css2?family=Gabarito:wght@500;700&family=Urbanist:wght@500;600;900&family=Sometype+Mono:wght@500&display=swap');
@import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:ital,wght@0,100..800;1,100..800&display=swap');
body,
html {
height: 100%;
background: var(--color-background);
margin: 0;
padding: 0;
}
h1 {
margin-top: 0.5rem;
margin-bottom: 1rem;
font-weight: 800;
font-size: var(--2-rem);
}
h2 {
font-weight: 600;
font-size: var(--1-4-rem);
}
:root {
--color-title: #071952;
--color-subtitle: #0C356A;
--color-special: #0174BE;
--color-text: #261C2C;
--color-subtext: #413543;
--color-hiddentext: #AA94AD;
--color-background: #F8F1F1;
--color-code: #ECE6F1;
--color-pill: #D0D4CA;
--palette-pink: #ad62aa;
--palette-red: #9A031E;
--palette-orange: #FF5B22;
--palette-yellow: #ff9843;
--palette-green: #0d9276;
--palette-purple: #4B1E78;
--palette-brown: #3c2317;
--background-light: linear-gradient(180deg, rgba(248, 241, 241, 1) 0%, rgba(15, 11, 17, 0.1) 100%);
--background-dark: linear-gradient(180deg, rgba(248, 241, 241, 1) 0%, rgba(224, 217, 217, 1) 100%);
--z-index-last: -1;
--z-index-normal: 0;
--z-index-front: 1;
--z-index-navbar: 2;
--z-index-popup: 3;
--border-min: 0.5rem;
--border-max: 2rem;
--profile-content-width-max: 40rem;
--profile-content-width-min: 36rem;
--width-min-desktop: 1275px;
--width-mobile: 875px;
/* https://clamp.font-size.app/
min=875px max=1100px */
--1-rem: clamp(0.75rem, -0.2222rem + 1.7778vw, 1rem);
--1-2-rem: clamp(0.9rem, -0.2667rem + 2.1333vw, 1.2rem);
--1-6-rem: clamp(1.2rem, -0.3556rem + 2.8444vw, 1.6rem);
--2-rem: clamp(1.4rem, -0.834rem + 4.0851vw, 2rem);
--navbar-height: 6rem;
--transition: all .4s ease 0s;
}
.base {
z-index: var(--z-index-front);
position: relative;
}
.title {
color: var(--color-background);
font-family: Gabarito;
font-weight: 700;
cursor: default;
transition: var(--transition);
font-size: 1.5rem;
margin: 0;
}
.flex-row {
display: flex;
align-items: center;
flex-direction: row;
}
.flex-col {
display: flex;
flex-direction: column;
}
.flex-start {
align-self: flex-start;
}
.flex-end {
margin-left: auto !important;
}
.shadow {
box-shadow: #41354340 0px 8px 18px -1px;
}
.h-100 {
height: 100%;
}
.h-70 {
height: 60%;
}
.h-fit {
height: fit-content;
}
.flex {
display: flex;
}
.align-center {
align-items: center;
}
.justify-center {
justify-content: center;
}
.center {
align-items: center;
justify-content: center;
}
.margin-padding-0 {
margin: 0;
padding: 0;
}
.margin-bottom {
margin-bottom: 0.5rem;
}
.margin-horizontal-05 {
margin-top: 0.5rem;
margin-bottom: 0.5rem;
}
.margin-left-3 {
margin-left: 3rem;
}
.margin-right-2 {
margin-right: 2rem;
}
.margin-05 {
margin-left: 0.5rem;
}
.padding-left-3 {
padding-left: 3rem;
}
.relative {
position: relative;
}
.inherit-w-h {
width: inherit;
height: inherit;
}
.text-justify {
text-align: justify;
text-justify: inter-word;
}
.disabled {
display: none !important;
}

View file

@ -0,0 +1,36 @@
.button-slider-container {
display: flex;
width: var(--button-slider-width);
height: 3.5rem;
background: var(--background-dark);
border-radius: 3rem;
padding: 0 !important;
box-shadow: 0px 8px 18px -1px rgba(52, 42, 58, 0.2);
}
.button-slider-active {
background-image: linear-gradient(to right, var(--navbar-dark) 0%, var(--navbar-light) 100%);
box-shadow: 0px 8px 18px -1px #33283760;
}
.button-slider-active span {
color: var(--color-background) !important;
}
.button-slider-container button {
background-color: #00000000;
font-family: 'JetBrains Mono';
border-radius: 3rem;
height: 2.5rem;
display: flex;
align-items: center;
margin-left: 0.5rem;
margin-right: 0.5rem;
border: none;
cursor: pointer;
}
.button-slider-container span {
padding: 1.6rem;
color: var(--color-text);
}

93
src/lib/css/carousel.css Normal file
View file

@ -0,0 +1,93 @@
.carousel-v-main {
padding: 1rem;
margin-left: 10dvw;
width: 80dvw;
display: flex;
flex-direction: row;
height: calc(50dvh + 2rem*3);
font-family: Urbanist;
font-weight: 500;
font-size: 1.1rem;
padding-bottom: 3rem;
}
.carousel-v-bigpost {
display: flex;
width: 50%;
height: 100%;
box-shadow: #00000040 0px 8px 18px -1px;
transition: all .1s ease 0s;
background-color: var(--color-background);
z-index: 2;
margin-right: 1rem;
margin-top: 2rem;
margin-bottom: 2rem;
}
.carousel-v-bigpost>div {
display: flex;
flex-direction: column;
margin: 1rem;
}
.carousel-picture {
width: 90%;
height: auto;
object-fit: cover;
}
.carousel-v-minpost-container {
display: flex;
flex-direction: column;
overflow: hidden;
position: relative;
width: 50%;
height: 100%;
padding-top: 2rem;
padding-bottom: 2rem;
}
.carousel-v-main h2 {
font-family: Gabarito;
font-weight: 500;
}
.carousel-v-main svg {
margin-right: 1rem;
}
.carousel-v-bigpost:hover, .carousel-v-minpost:hover {
cursor: pointer;
transform: scale(1.01) translateY(-4px);
}
.carousel-v-minpost {
display: flex;
flex-direction: row;
height: calc(50dvh/3);
padding: 1rem;
box-shadow: #00000040 0px 8px 18px -1px;
transition: all .1s ease 0s;
margin-right: 1rem;
margin-left: 1rem;
background-color: var(--color-background);
}
.carousel-v-minpost img {
min-width: 40%;
max-width: 40%;
height: 100%;
object-fit: cover;
margin: 0;
margin-right: 1rem;
}
.carousel-v-minpost h2 {
margin: 0;
margin-bottom: 0.5rem;
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
font-size: 1.4rem;
}

19
src/lib/css/count.css Normal file
View file

@ -0,0 +1,19 @@
.count {
display: flex;
flex-direction: column;
padding: 1rem;
margin-left: 1rem;
margin-right: 1rem;
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;
}
.count h1 {
margin: 0;
}
.count h2 {
margin: 0;
font-weight: 400;
}

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

@ -0,0 +1,75 @@
:root {
--ratio-container: 0.7;
--ratio-content: 50%;
--height-footer: 25rem;
}
.footer-container:before {
content: "";
position: absolute;
left: 0;
height: 4rem;
top: -2rem;
width: 100%;
background-color: var(--color-background);
border-radius: var(--border-max);
}
.footer-container {
position: relative;
flex-direction: column;
margin-top: 3rem;
padding-top: 2rem;
height: var(--height-footer);
background-image: linear-gradient(to right, var(--navbar-dark) 0%, var(--navbar-light) 100%);
box-shadow: rgba(72, 50, 93, 0.2) 0px 120px 60px -20px inset, rgba(0, 0, 0, 0.4) 0px 100px 60px -18px inset;
}
.footer-content {
width: inherit;
height: calc(var(--ratio-container) * var(--height-footer));
display: flex;
flex-direction: row;
}
.footer-left {
flex-basis: calc(100% - var(--ratio-content));
display: flex;
justify-content: center;
align-items: center;
}
.footer-left h1 {
font-size: 3rem;
}
.footer-right {
flex-basis: var(--ratio-content);
padding: 2rem;
overflow: hidden;
}
.footer-slider {
width: inherit;
height: auto;
padding: 1rem;
display: flex;
}
.footer-slider > span {
font-family: 'JetBrains Mono';
padding-left: 2rem;
color: var(--color-hiddentext);
font-size: var(--1-rem);
}
.footer-slider div {
padding-right: 2rem;
}
.footer-page {
min-height: 15rem;
max-height: 15rem;
display: flex;
flex-direction: column;
}

View file

@ -0,0 +1,70 @@
.page-icon-text > a {
text-decoration: none;
position: relative;
font-size: var(--1-2-rem);
transition: var(--transition);
}
.page-icon-text h1 {
font-size: var(--1-6-rem);
}
.page-icon-text > a:hover {
color: var(--palette-pink);
}
.page-icon-text > a::after {
content: "";
display: block; /* Ensure the pseudo-element takes up space */
position: absolute;
height: 0.2rem;
background-color: var(--palette-pink);
width: 0%;
transition: var(--transition);
}
.page-icon-text > a:hover::after {
width: 100%;
}
.page-icon-text {
color: var(--color-background);
font-family: 'JetBrains Mono';
font-weight: 500;
display: flex;
align-items: center;
padding: 0.5rem;
}
.page-icon-text i {
font-weight: 700;
font-size: var(--1-6-rem);
color: var(--color-hiddentext);
cursor: default;
}
.page-special svg {
padding-left: 2rem;
color: var(--color-hiddentext);
}
.page-icon-text img, .page-icon-text svg {
/* width: calc(calc(((var(--page-height)*var(--ratio-container-float))) - 4rem)*(1/4)); */
width: 1.8rem;
height: auto;
padding-right: 2rem;
}
.page-text {
color: var(--color-hiddentext);
font-family: 'JetBrains Mono';
font-weight: 400;
font-size: var(--1-rem);
display: flex;
align-items: center;
padding: 0.5rem;
}
.page-overflow {
max-height: 10rem;
}

83
src/lib/css/link.css Normal file
View file

@ -0,0 +1,83 @@
:root {
--line-size: 5px;
}
.link-container {
width: 60rem;
height: 20rem;
margin-bottom: 2rem;
cursor: pointer;
transition: var(--transition);
display: grid;
border-radius: 1rem;
grid-template-areas:
"overlay";
}
.link-container:hover {
box-shadow: var(--shadow);
}
.link-container svg {
margin-left: 1rem;
color: var(--color-text);
transition: var(--transition);
}
.link-img {
display: grid;
grid-template-areas:
"overlay";
max-width: 30rem;
height: 20rem;
}
.link-img img {
grid-area: overlay;
height: 100%;
width: auto;
}
.link-img-hover {
opacity: 0;
}
.link-content {
grid-area: overlay;
width: 60rem;
height: 20rem;
border-radius: 1rem;
}
.link-background {
grid-area: overlay;
width: 60rem;
height: 20rem;
border-radius: 1rem;
opacity: 0;
background-image: var(--gradient);
}
/* Link Underlined */
.link-content>span {
font-family: 'JetBrains Mono';
font-weight: 500;
font-size: 2.5rem;
text-decoration: none;
position: relative;
color: var(--color-text);
transition: var(--transition);
}
.link-content>span::after {
content: "";
position: absolute;
background-color: var(--color-background);
height: var(--line-size);
bottom: calc(0px - var(--line-size));
height: var(--line-size);
left: 0;
transition: var(--transition);
width: var(--span-width);
}

32
src/lib/css/main.css Normal file
View file

@ -0,0 +1,32 @@
:root {
--banner-height: 60vh;
}
.main-banner {
display: grid;
grid-template-areas:
"overlay";
width: 100%;
}
.main-banner-gradient {
grid-area: overlay;
background: linear-gradient(0deg, #00000000, #261C2C20 50%, #261c2c40 100%);
height: calc(var(--navbar-height)*2);
}
.main-banner-content {
grid-area: overlay;
margin-top: var(--navbar-height);
}
.main-banner-content img {
width: 40dvw;
}
.main-banner-content h1 {
color: var(--color-text);
font-family: Gabarito;
font-weight: 700;
font-size: 3rem;
}

176
src/lib/css/navbar.css Normal file
View file

@ -0,0 +1,176 @@
:root {
--navbar-dark: #261C2CFF;
--navbar-darker: #261C2CFF;
--navbar-light: #413543FF;
--navbar-ligher: #413543FF;
--navbar-outline: 2px solid rgb(40, 32, 44, 0.5);
--navbar-inset: inset 0px 0px 0px 2px rgba(52, 42, 58, 0.5);
--navbar-blur: blur(0.6rem);
}
nav {
height: var(--navbar-height);
width: 100%;
position: fixed;
z-index: 5;
transition: var(--transition);
padding-top: 0.5rem;
}
a {
color: var(--color-background);
}
.navbar-background {
border-radius: var(--border-min);
background-image: linear-gradient(to right, var(--navbar-dark) 0%, var(--navbar-light) 100%);
height: 90%;
margin: 0.5rem;
}
/* Background */
.container {
display: grid;
grid-template-areas:
"navbar-overlay-back"
"navbar-overlay-front"
"content";
}
.navbar-overlay-front {
grid-area: overlay;
background-image: linear-gradient(to right, var(--navbar-dark) 0%, var(--navbar-light) 100%);
width: inherit;
height: inherit;
border-radius: var(--border-min);
box-shadow: rgba(52, 42, 58, 0.25) 0px 50px 100px -20px, rgba(0, 0, 0, 0.3) 0px 30px 60px -30px, var(--navbar-inset);
outline: 2px solid rgb(40, 32, 44, 0.5);
}
.navbar-overlay-back {
grid-area: overlay;
width: inherit;
height: inherit;
border-radius: var(--border-min);
box-shadow: var(--navbar-inset);
outline: var(--navbar-outline)
}
.content {
grid-area: overlay;
z-index: 1;
width: inherit;
display: flex;
}
/* Each element */
.navbar-height {
height: var(--navbar-height);
padding-left: 0.5rem;
padding-right: 0.5rem;
}
.navbar-title {
margin-left: 3rem;
margin-right: 3rem;
}
.navbar-categories {
align-items: center;
height: var(--navbar-height);
padding-left: 1rem;
padding-right: 1rem;
}
.navbar-categories a {
text-decoration: none;
font-family: JetBrains Mono;
font-weight: 500;
font-size: 1rem;
transition: var(--transition);
color: var(--color-background);
transition: var(--transition);
}
.navbar-categories div {
position: relative;
margin-left: 1rem;
margin-right: 1rem;
}
.navbar-categories>div>a::before,
.navbar-categories>div>a::after {
content: "";
position: absolute;
width: 0;
background-color: var(--palette-pink);
transition: var(--transition);
height: 3px;
}
.navbar-categories>div>a::before {
top: -3px;
height: 3px;
}
.navbar-categories>div>a::after {
bottom: -3px;
height: 3px;
right: 0;
}
.navbar-categories>div>a:hover::before,
.navbar-categories>div>a:hover::after {
width: 100%;
}
.navbar-categories>div>a:hover {
color: var(--palette-pink);
}
.navbar-search {
justify-content: center;
padding-right: 1rem;
padding-left: 1rem;
}
.navbar-search-floating input {
margin-top: 0 !important;
background-color: var(--color-background) !important;
color: var(--color-subtext) !important;
border-color: var(--color-pill) !important;
}
/* Floating */
.floating {
background-image: linear-gradient(to right, #241d25c4 0%, #3d2b47c4 100%);
box-shadow: rgba(52, 42, 58, 0.25) 0px 50px 100px -20px, rgba(0, 0, 0, 0.3) 0px 30px 60px -30px;
border-bottom-left-radius: 2rem;
border-bottom-right-radius: 2rem;
padding-top: 0;
-webkit-backdrop-filter: var(--navbar-blur);
backdrop-filter: var(--navbar-blur);
}
.floating>div {
display: flex;
align-items: center;
flex-direction: row;
}
/* Active */
.navbar-active {
color: var(--palette-pink) !important;
cursor: default;
}
.navbar-active::after {
width: 100% !important;
}
.navbar-active::before {
width: 0 !important;
}

69
src/lib/css/pill.css Normal file
View file

@ -0,0 +1,69 @@
.pill {
align-items: center;
display: flex;
flex-direction: row;
font-weight: 600;
background-color: #00000000;
border-radius: 3rem;
box-shadow: 0px 8px 18px -1px rgba(52, 42, 58, 0.2);
margin: 0.5rem;
}
.pill-reversed {
padding: 0 !important;
justify-content: flex-end;
}
.pill img {
border-radius: 100% !important;
width: 3rem !important;
height: 3rem !important;
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;
}
.pill-profile:hover {
background: var(--color-text);
box-shadow: 0px 8px 18px -1px #413543A0;
}
.pill-profile:hover span {
color: var(--color-background) !important;
}
.pill-reversed svg {
margin-left: 1rem;
margin-right: 0;
}
.pill span {
font-size: var(--1-rem);
font-style: normal;
color: var(--color-text);
transition: all .4s ease 0s;
/* Overflow */
overflow: hidden;
white-space: nowrap;
text-overflow: ".";
max-width: var(--width-pill);
padding-right: 1rem;
}
.pill-reversed span {
padding-right: 0;
padding-left: 1rem;
}

101
src/lib/css/post-min.css vendored Normal file
View file

@ -0,0 +1,101 @@
@media screen and (max-width: 1275px) {
.post-min-container {
height: calc(var(--profile-content-width-min)/2);
width: calc((var(--profile-content-width-min) + 6rem - 4rem)/3);
}
.post-min {
height: calc(var(--profile-content-width-min)/2);
}
.post-min img {
max-height: calc(var(--profile-content-width-min)/4);
}
}
@media screen and (min-width: 1276px) {
.post-min-container {
height: calc(var(--profile-content-width-max)/2);
width: calc((var(--profile-content-width-max) + 6rem - 4rem)/3);
}
.post-min {
height: calc(var(--profile-content-width-max)/2);
}
.post-min img {
max-height: calc(var(--profile-content-width-max)/4);
}
}
.post-min-container {
display: grid;
grid-template-areas:
"post-min-overlay-back"
"post-min-overlay-front"
"post-min";
margin-left: 1rem;
margin-right: 1rem;
}
.post-min {
cursor: pointer;
display: flex;
flex-direction: column;
grid-area: overlay;
z-index: var(--z-index-front);
}
.post-min 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;
}
.post-min h1 {
font-weight: 800;
font-size: 1.1rem;
margin-left: 1rem;
margin-right: 1rem;
/* Overflow */
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
text-overflow: ellipsis;
-webkit-line-clamp: 3;
line-clamp: 3;
}
.post-min-overlay-front {
grid-area: overlay;
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;
}
.post-min-overlay-back {
grid-area: overlay;
border-radius: 1rem;
}
.post-min-pill {
height: 2rem;
width: auto;
margin: 1rem;
margin-top: auto !important;
}
.post-min-pill span {
font-size: 0.8rem;
}
.post-min-pill svg {
width: 1.2rem !important;
height: 1.2rem !important;
padding: calc((2rem - 1.2rem)/2);
}

117
src/lib/css/post.css Normal file
View file

@ -0,0 +1,117 @@
:root {
--width-max-post: 60rem;
--width-min-post: 50rem;
--height-post: 20rem;
--width-picture: 25rem;
--ratio-picture: 0.5;
}
@media screen and (max-width: 1075px) {
.post-container {
width: var(--width-min-post);
}
.post-text {
width: calc(var(--width-min-post) - var(--width-picture) - 4rem);
}
}
@media screen and (min-width: 1076px) {
.post-container {
width: var(--width-max-post);
}
.post-text {
width: calc(var(--width-max-post) - var(--width-picture) - 4rem);
}
}
/* Post */
.post-container {
display: grid;
grid-template-areas:
"post-overlay-back"
"post-overlay-front"
"post";
height: var(--height-post);
}
.post-overlay-front {
grid-area: overlay;
background-image: var(--background-light);
border-radius: 1rem;
box-shadow: rgba(79, 50, 93, 0.25) 0px 30px 60px -12px, rgba(0, 0, 0, 0.3) 0px 18px 36px -18px;
}
.post-overlay-back {
grid-area: overlay;
border-radius: 1rem;
}
.post {
cursor: pointer;
display: flex;
grid-area: overlay;
z-index: var(--z-index-front);
}
.post img {
width: var(--width-picture);
height: var(--height-post);
object-fit: cover;
border-top-left-radius: 1rem;
border-bottom-left-radius: 1rem;
border-top-right-radius: 0.6rem;
border-bottom-right-radius: 0.6rem;
margin-right: 1rem;
}
.post-text {
font-family: 'JetBrains Mono';
justify-content: space-between;
display: flex;
flex-direction: column;
margin: 1rem;
margin-right: 2rem;
}
.text-container {
margin-top: 1rem;
margin-bottom: 1rem;
display: flex;
flex-direction: row;
}
.post-text h1 {
font-weight: 800;
font-size: var(--1-6-rem);
margin-top: 1rem;
margin-bottom: 1rem;
/* Overflow */
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
text-overflow: ellipsis;
-webkit-line-clamp: 2;
line-clamp: 2;
}
.post-text p {
font-size: 1rem;
font-style: italic;
color: var(--color-subtext);
text-align: justify;
text-justify: auto;
/* Overflow */
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
text-overflow: ellipsis;
-webkit-line-clamp: 3;
line-clamp: 3;
}
.post-author-pill {
width: 100%;
}

View file

@ -0,0 +1,136 @@
:root {
--banner-height: 30vw;
--picture-width: 15rem;
--picture-left: 5vw;
--picture-border: 1.5rem;
}
@media screen and (max-width: 1275px) {
.profile-post-container {
width: calc(var(--profile-content-width-min) + 6rem);
}
.profile-content {
width: var(--profile-content-width-min);
}
}
@media screen and (min-width: 1276px) {
.profile-post-container {
width: calc(var(--profile-content-width-max) + 6rem);
}
.profile-content {
width: var(--profile-content-width-max);
}
}
.profile {
font-family: 'JetBrains Mono';
color: var(--color-text);
}
.profile h1 {
margin: 0;
}
.profile-title {
margin-bottom: 2rem !important;
margin-left: 2rem !important;
}
.profile p {
text-align: justify;
text-justify: auto;
}
.profile-banner {
display: grid;
grid-template-areas:
"profile-banner-gradient"
"profile-banner-img"
"profile-banner-profile";
height: var(--banner-height);
width: 100%;
}
.profile-banner-gradient {
grid-area: overlay;
background: linear-gradient(0deg, #00000000, #261C2C70 50%, #261C2CC0 100%);
height: calc(var(--navbar-height)*2);
}
.profile-banner-img {
grid-area: overlay;
z-index: var(--z-index-last);
}
.profile-banner-img img {
object-fit: cover;
width: 100dvw;
height: var(--banner-height);
}
.profile-banner-profile {
grid-area: overlay;
position: absolute;
top: calc(var(--banner-height) - var(--picture-width)*2/5);
left: var(--picture-left);
}
.profile-banner-profile img {
width: var(--picture-width);
height: var(--picture-width);
border-radius: 100%;
border: var(--picture-border) solid;
color: var(--color-background);
}
.profile-name {
display: flex;
height: 8rem;
margin-left: calc(var(--picture-left) + var(--picture-width) + var(--picture-border)*2);
}
.profile-name > span {
background-color: var(--color-pill);
margin-left: 1rem;
margin-right: 1rem;
padding: 0.5rem;
border-radius: var(--border-min);
font-size: var(--1-2-rem);
}
.profile-slider {
margin-top: 3rem;
margin-bottom: 2rem;
}
.profile-main {
width: 100%;
display: flex;
}
.profile-container {
display: flex;
flex-direction: column;
margin-bottom: 2rem;
margin-left: 1rem;
margin-right: 1rem;
}
.profile-container>div {
margin-bottom: 2rem;
}
.profile-post-container {
display: flex;
flex-direction: row;
}
.profile-content {
padding: 3rem;
border-radius: 1rem;
box-shadow: rgba(79, 50, 93, 0.25) 0px 30px 60px -12px, rgba(0, 0, 0, 0.3) 0px 18px 36px -18px;
background-image: var(--background-light);
}

47
src/lib/css/search.css Normal file
View file

@ -0,0 +1,47 @@
.search {
display: flex;
flex-direction: row;
box-shadow: rgba(79, 50, 93, 0.25) 0px 30px 60px -12px, rgba(0, 0, 0, 0.3) 0px 18px 36px -18px;
border-radius: 5rem;
background-color: var(--color-background);
margin: 0 !important;
}
.search input {
padding-left: 0.5rem;
background-color: var(--color-background);
font-family: 'JetBrains Mono';
background-color: #00000000;
border: 0;
width: 100%;
border-top-right-radius: 5rem;
border-bottom-right-radius: 5rem;
}
.search input:focus {
border: 0;
outline: none;
}
.search svg {
color: var(--color-background);
background-color: var(--color-text);
border-radius: 100%;
box-shadow: #4f325d40 15px 0px 60px -12px, #0000004d 15px 0px 36px -18px;
background: radial-gradient(circle farthest-corner at 0px 0px, var(--color-subtext) 0%, var(--color-text) 80%);
cursor: pointer;
transform: scale(1.1) !important;
}
.search-box {
width: inherit;
height: 16rem;
background-color: var(--color-background);
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;
position: absolute !important;
z-index: 1;
transform: translateX(-1rem);
display: none;
opacity: 0;
}

105
src/lib/css/social.css Normal file
View file

@ -0,0 +1,105 @@
:root {
--social-max-width: 20rem;
--social-min-width: 2rem;
}
@media screen and (max-width: 1275px) {
.social-width {
width: var(--social-min-width);
}
.social-link span {
display: none;
}
.social h1 {
display: none;
}
.social-archive {
width: calc(var(--profile-content-width-min) + 6rem);
}
}
@media screen and (min-width: 1276px) {
.social-width {
width: var(--social-max-width);
}
.social-link span {
text-decoration: none;
position: relative;
color: var(--color-text);
margin-left: auto;
font-size: 1.4rem;
font-weight: 500;
}
.social-archive {
width: calc(var(--social-max-width) + 4rem);
}
}
.social {
padding: 3rem;
padding-right: 2rem;
padding-left: 2rem;
border-radius: 1rem;
box-shadow:
rgba(79, 50, 93, 0.25) 0px 30px 60px -12px,
rgba(0, 0, 0, 0.3) 0px 18px 36px -18px;
background-image: var(--background-light);
}
.social-link {
height: 2rem;
display: flex;
flex-direction: row;
margin-top: 1.2rem;
margin-bottom: 1.2rem;
cursor: pointer;
transition: var(--transition);
}
.social-link img {
height: 2rem;
width: 2rem;
transition: var(--transition);
}
.social-link img:hover {
filter: drop-shadow(0px 4px 8px var(--social-color));
}
.social-link svg {
transition: var(--transition);
}
.social-link svg:hover {
filter: drop-shadow(0px 0px 8px var(--social-color));
}
/* Underline links */
.social-link span:hover {
color: var(--social-color);
}
.social-link span::after {
content: "";
position: absolute;
width: 0;
background-color: var(--social-color);
transition: var(--transition);
height: 3px;
}
.social-link span::after {
bottom: -3px;
height: 3px;
right: 0;
}
.social-link span:hover::after {
width: 100%;
}

4
src/lib/css/style.css Normal file
View file

@ -0,0 +1,4 @@
.blank {
height: 10rem;
background-color: #00000000;
}

28
src/lib/ts/color.ts Normal file
View file

@ -0,0 +1,28 @@
type RGB = {
r: number;
g: number;
b: number;
};
export function hexTorgb(hex: string) {
return {
r: parseInt(hex.substring(0, 2), 16),
g: parseInt(hex.substring(2, 4), 16),
b: parseInt(hex.substring(4, 6), 16),
}
}
/* should be type {r,g,b} */
export function rgbTohex(rgb: RGB) {
return (rgb.r.toString(16) + rgb.g.toString(16) + rgb.b.toString(16));
}
export function darkenHexTorgb(hex: string, darken: number) {
let rgb = hexTorgb(hex);
console.log(hex);
console.log(rgb);
rgb.r = Math.floor(Math.round(rgb.r * darken));
rgb.g = Math.floor(Math.round(rgb.g * darken));
rgb.b = Math.floor(Math.round(rgb.b * darken));
return rgb;
}

16
src/routes/+layout.svelte Normal file
View file

@ -0,0 +1,16 @@
<script>
import { page } from '$app/stores';
import '$lib/css/base.css';
import '$lib/css/navbar.css';
import Navbar from '$lib/components/navbar.svelte';
import Footer from '$lib/components/footer.svelte';
// $: pageUrl = $page.url.pathname;
</script>
<Navbar />
<div class="base">
<slot />
</div>
<Footer />

View file

@ -1,2 +1,16 @@
<h1>Welcome to SvelteKit</h1>
<p>Visit <a href="https://svelte.dev/docs/kit">svelte.dev/docs/kit</a> to read the documentation</p>
<script>
import '$lib/css/base.css';
import '$lib/css/main.css';
import Link from '$lib/components/link.svelte';
let img = 'placeholder.png';
</script>
<div class="main-banner">
<div class="main-banner-gradient" />
<div class="main-banner-content">
<div class="flex-row center" style="padding-top: 15rem;padding-bottom: 15rem;">
<h1>Welcome to Etheryo</h1>
</div>
</div>
</div>