Skip to content

Commit

Permalink
Technologies section (#85)
Browse files Browse the repository at this point in the history
Co-authored-by: MinixBF <[email protected]>
  • Loading branch information
WarningImHack3r and MinixBF authored Sep 4, 2023
1 parent 5f0be0c commit 2539cb2
Show file tree
Hide file tree
Showing 3 changed files with 216 additions and 2 deletions.
15 changes: 15 additions & 0 deletions src/locales/en/home.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,21 @@
"desc": "We make sure that your project is as fast as possible, to offer the best possible experience to your users."
}
},
"technologies": {
"title": "The [technologies] we use",
"framework": {
"title": "Framework: [SvelteKit]",
"desc": "Svelte, with its SvelteKit metaframework, gives us unrivalled performance and a simple, pleasant development experience."
},
"database": {
"title": "Database: [PostgreSQL]",
"desc": "PostgreSQL is a powerful, reliable and proven database, perfect for storing your data securely."
},
"infrastructure": {
"title": "Infrastructure: [Vercel]",
"desc": "Vercel is a high-performance cloud platform designed for SvelteKit, enabling us to host your project in the best possible conditions."
}
},
"about-us": {
"title": "About us",
"desc": "We are three co-founders who share the same passion for taking on challenges. After our engineering school, we realized that we complemented each other both in terms of human interaction and technical skills. Too often, we come across websites or applications with bugs or maintenance problems. That's why we want to use our skills to help start-ups and companies meet their needs by creating high-quality solutions.",
Expand Down
15 changes: 15 additions & 0 deletions src/locales/fr/home.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,21 @@
"desc": "Nous nous assurons que votre projet soit rapide et efficace, afin d'offrir la meilleure expérience utilisateur possible."
}
},
"technologies": {
"title": "Les [technologies] que nous utilisons",
"framework": {
"title": "Framework : [SvelteKit]",
"desc": "Svelte, avec son metaframework SvelteKit, nous permet de bénéficier de performances inégalées et d'une expérience de développement simple et agréable."
},
"database": {
"title": "Base de données : [PostgreSQL]",
"desc": "PostgreSQL est une base de données puissante, fiable et éprouvée, parfaite pour stocker vos données en toute sécurité."
},
"infrastructure": {
"title": "Infrastructure : [Vercel]",
"desc": "Vercel est une plateforme cloud qui nous permet d'héberger votre projet de façon très performante, car conçue pour SvelteKit."
}
},
"about-us": {
"title": "À propos de [nous]",
"desc": "Nous sommes trois cofondateurs qui partagent la même passion pour les défis. Après notre école d'ingénieur, nous avons réalisé que nous étions complémentaires tant au niveau de l'interaction humaine que des compétences techniques. Trop souvent, nous rencontrons des sites web ou des applications avec des bugs ou des problèmes de maintenance. C'est pourquoi nous voulons mettre nos compétences au service des start-ups et des entreprises pour les aider à répondre à leurs besoins en créant des solutions de qualité.",
Expand Down
188 changes: 186 additions & 2 deletions src/routes/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script lang="ts">
import { ROOT_URL } from "$config";
import type { SvelteComponent } from "svelte";
import { onMount, type SvelteComponent } from "svelte";
import type { SvelteHTMLElements } from "svelte/elements";
import { goto } from "$app/navigation";
import MagneticElement from "$shells/MagneticElement.svelte";
Expand All @@ -25,6 +25,7 @@
CodeBracket,
DevicePhoneMobile
} from "@inqling/svelte-icons/heroicon-24-solid";
import { Postgresql, Svelte, Vercel } from "@inqling/svelte-icons/simple-icons";
import { i, language } from "@inlang/sdk-js";
import { c } from "$utils/inlang-color";
import resolveConfig from "tailwindcss/resolveConfig";
Expand All @@ -47,6 +48,7 @@
title: string;
description: string;
}[] = [];
let technologiesSections: typeof processSections & { brandColor: string }[] = [];
$: if (language) {
processSections = [
{
Expand Down Expand Up @@ -114,6 +116,50 @@
description: i("home.values.performance.desc")
}
];
technologiesSections = [
{
title: c(i("home.technologies.framework.title")),
icon: Svelte,
brandColor: "#FF3E00",
description: i("home.technologies.framework.desc")
},
{
title: c(i("home.technologies.database.title")),
icon: Postgresql,
brandColor: "#4169E1",
description: i("home.technologies.database.desc")
},
{
title: c(i("home.technologies.infrastructure.title")),
icon: Vercel,
brandColor: "#FFFFFF",
description: i("home.technologies.infrastructure.desc")
}
];
}
// Technologies cards
let technoCards: HTMLElement;
let technoIcons: HTMLElement;
function getOffset(
totalPoints: number,
pointNumber: number,
radius: number = 60,
clockwise: boolean = true
) {
if (pointNumber > totalPoints) {
throw new Error("Point number cannot exceed total number of points.");
}
const baseAngle = ((2 * Math.PI) / totalPoints) * pointNumber;
const angle = clockwise ? baseAngle : 2 * Math.PI - baseAngle;
return {
x: radius * Math.cos(angle),
y: radius * Math.sin(angle)
};
}
// Keep only 3 solutions sections if screen is too small
Expand All @@ -125,6 +171,92 @@
solutions = solutionsSections;
}
}
// Auto-scroll technologies cards
const DELAY = 5000;
let currentCard = 0;
function hoverIcon(index: number) {
const icons = technoIcons.children;
if (!icons || icons.length < index) return;
const icon = icons[index];
if (!icon) return;
icon.classList.add("is-selected");
for (let i = 0; i < icons.length; i++) {
if (i === index) continue;
icons[i]?.classList.remove("is-selected");
}
}
function scrollToCard(index: number) {
const cards = technoCards?.children;
if (!cards || cards.length < index) return;
const card = cards[index];
if (!card) return;
technoCards.scrollTo({
left: card.clientWidth * index,
behavior: "smooth"
});
}
onMount(() => {
// === Auto-scroll technologies cards ===
// Initial checks
const cards = technoCards?.children;
if (!cards || cards.length < 2) return;
// Hover the first icon on load, otherwise
// no icon is hovered until the first scroll
hoverIcon(currentCard);
// Auto-scroll function
const autoScroll = () => {
if (currentCard === cards.length - 1) {
currentCard = 0;
} else {
currentCard++;
}
scrollToCard(currentCard);
};
// Initial interval definition, start auto-scrolling
let interval = setInterval(autoScroll, DELAY);
// Stop the interval on hover of the cards
technoCards.addEventListener("mouseenter", () => {
clearInterval(interval);
});
// Restart the interval on mouse leave
technoCards.addEventListener("mouseleave", () => {
interval = setInterval(autoScroll, DELAY);
});
// Add listeners to the icons to start/stop the interval on hover
[...technoIcons.children].forEach(icon => {
icon.addEventListener("mouseenter", () => {
clearInterval(interval);
});
icon.addEventListener("mouseleave", () => {
interval = setInterval(autoScroll, DELAY);
});
});
// Scroll handler to update the hovered icon depending on
// the card we scrolled to
technoCards.addEventListener("scrollend", () => {
const scrollDistance = technoCards.scrollLeft;
const containerWidth = technoCards.clientWidth;
currentCard = Math.round(scrollDistance / containerWidth);
hoverIcon(currentCard);
});
// On destroy, clear the interval
return () => clearInterval(interval);
});
</script>

<!-- Window bindings -->
Expand Down Expand Up @@ -349,7 +481,7 @@
</div>
</Section>

<!-- Our Values -->
<!-- Values -->
<Section id="values" class="relative py-20">
<svelte:fragment slot="title">
<!-- eslint-disable-next-line svelte/no-at-html-tags -->
Expand All @@ -371,6 +503,58 @@
</div>
</div>
</Section>

<!-- Technologies -->
<Section id="technologies">
<svelte:fragment slot="title">
<!-- eslint-disable-next-line svelte/no-at-html-tags -->
{@html c(i("home.technologies.title"))}
</svelte:fragment>
<div class="flex flex-col items-center gap-8 sm:flex-row">
<!-- Left part -->
<div
bind:this={technoCards}
class="flex max-w-full snap-x snap-mandatory gap-8 overflow-x-auto py-4 child:snap-start sm:max-w-none"
>
{#each technologiesSections as techno}
<div class="flex min-w-full flex-col gap-4 rounded-3xl backdrop-filter backdrop-blur border border-opacity-25 border-white bg-glass p-8">
<!-- eslint-disable-next-line svelte/no-at-html-tags -->
<h3 class="text-xl font-medium">{@html techno.title}</h3>
<p class="text-lg text-gray-200">
{techno.description}
</p>
</div>
{/each}
</div>

<!-- Right part -->
<div class="aspect-square h-56 lg:h-48">
<div
bind:this={technoIcons}
class="relative flex h-full w-full items-center justify-center -rotate-45"
>
{#each technologiesSections as techno, index}
{@const { x, y } = getOffset(technologiesSections.length, index, 50, false)}
<button
style="transform: translate({x}%, {y}%);"
class="group absolute flex aspect-square h-1/2 items-center justify-center rounded-full bg-gray-400/75 transition-all duration-700
hover:bg-gray-500 hover:scale-110
[&.is-selected]:z-10 [&.is-selected]:bg-gray-600 [&.is-selected]:scale-110"
on:click={() => scrollToCard(index)}
>
<svelte:component
this={techno.icon}
style="--brand-color: {techno.brandColor}"
class="w-1/2 drop-shadow-md transition-all duration-700 rotate-45
group-hover:fill-[var(--brand-color)] group-hover:scale-110
group-[.is-selected]:fill-[var(--brand-color)] group-[.is-selected]:scale-110"
/>
</button>
{/each}
</div>
</div>
</div>
</Section>

<!-- About us -->
<Section id="about-us">
Expand Down

0 comments on commit 2539cb2

Please sign in to comment.