FEAT: Started fleshing out content on the webpage

This commit is contained in:
Luke Else 2025-05-23 18:13:58 +01:00
parent 538d9593c2
commit c52d185f76
Signed by: luke-else
GPG Key ID: B44FAF5CD3964A56
9 changed files with 159 additions and 130 deletions

View File

@ -1,19 +1,31 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="description" content="Luke Else - Software Developer at Thales UK. I specialise in developing distributed systems in C++ using highly scalable internal frameworks. I also develop backend and system applications in my spare time using both Svelte, Rust and C++. Feel free to check my work out at https://git.luke-else.co.uk." />
<head>
<meta charset="utf-8" />
<meta
name="description"
content="Luke Else - Software Developer at Thales UK. I specialise in developing distributed systems in C++ using highly scalable internal frameworks. I also develop backend and system applications in my spare time using both Svelte, Rust and C++. Feel free to check my work out at https://git.luke-else.co.uk."
/>
<meta name="author" content="Luke Else (mail@luke-else.co.uk)" />
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/devicons/devicon@v2.15.1/devicon.min.css">
<meta name="viewport" content="width=device-width" />
<script async src="https://tracking.luke-else.co.uk/tracker.js" data-ackee-server="https://tracking.luke-else.co.uk" data-ackee-domain-id="6c59ab88-dc6d-4d53-9831-0d6bff919dcd" data-ackee-opts='{ "detailed": true }'></script>
%sveltekit.head%
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/gh/devicons/devicon@v2.15.1/devicon.min.css"
/>
<meta name="viewport" content="width=device-width" />
<script
async
src="https://tracking.luke-else.co.uk/tracker.js"
data-ackee-server="https://tracking.luke-else.co.uk"
data-ackee-domain-id="6c59ab88-dc6d-4d53-9831-0d6bff919dcd"
data-ackee-opts='{ "detailed": true }'
></script>
%sveltekit.head%
<style>
</style>
</head>
<body data-sveltekit-preload-data="hover">
<div style="display: contents">%sveltekit.body%</div>
</body>
<style></style>
</head>
<body data-sveltekit-preload-data="hover">
<div style="display: contents">%sveltekit.body%</div>
</body>
</html>

View File

@ -3,24 +3,29 @@
export let headerRight: string = "";
export let headerColour: string = "text-red-500";
export let footer: string = "";
// Allows additional styling to be applied to the Card component's outer wrapping
export let containerStyle: string = "";
</script>
<div class="bg-slate-100/10 dark:bg-slate-100/10 rounded-2xl shadow-2xl p-6 flex flex-col h-full w-full">
<div class="{headerColour} flex flex-row justify-between items-center mb-4">
<p class="text-2xl md:text-3xl font-bold truncate">{headerLeft}</p>
{#if headerRight}
<p class="max-md:hidden text-xl md:text-2xl truncate">{@html headerRight}</p>
<div class={containerStyle}>
<div class="bg-slate-100/10 dark:bg-slate-100/10 rounded-2xl shadow-2xl p-6 flex flex-col h-full w-full">
<div class="{headerColour} flex flex-row justify-between items-center mb-4">
<p class="text-2xl md:text-3xl font-bold truncate">{headerLeft}</p>
{#if headerRight}
<p class="max-md:hidden text-xl md:text-2xl truncate">{@html headerRight}</p>
{/if}
</div>
<hr class="mb-4 border-1" />
<div class="flex-1 flex flex-col justify-center p-5">
<slot />
</div>
{#if footer}
<hr class="my-4 border-1" />
<div class="mt-2 text-base opacity-90">
{@html footer}
</div>
{/if}
</div>
<hr class="mb-4 border-1" />
<div class="flex-1 flex flex-col justify-center p-5">
<slot />
</div>
{#if footer}
<hr class="my-4 border-1" />
<div class="mt-2 text-base opacity-90">
{@html footer}
</div>
{/if}
</div>
</div>

View File

@ -0,0 +1,7 @@
<script lang="ts">
</script>
<!-- FlexGallery.svelte -->
<div class="flex flex-wrap gap-10 w-full">
<slot />
</div>

View File

@ -1,39 +0,0 @@
<script lang="ts">
export let showModal: boolean;
let dialog: HTMLDialogElement;
$: if (dialog && showModal) dialog.showModal();
import CloseIcon from "./Toasts/CloseIcon.svelte";
</script>
<!-- svelte-ignore a11y-click-events-have-key-events a11y-no-noninteractive-element-interactions -->
<dialog
bind:this={dialog}
on:close={() => (showModal = false)}
on:click|self={() => dialog.close()}
class="max-w-[70vw] rounded-md border-0 p-0 shadow-lg bg-bg text-fg relative animate-[zoom_0.5s_cubic-bezier(0.34,1.56,0.64,1)]"
style="box-shadow: 0.5em 0.5em 0.5em var(--header);"
>
<!-- svelte-ignore a11y-no-static-element-interactions -->
<div on:click|stopPropagation class="p-4">
<slot name="header" />
<hr class="my-2 border-accent" />
<slot />
<hr class="my-2 border-accent" />
</div>
<button
class="close absolute top-4 right-6 text-fg bg-transparent border-0 p-0 m-0 leading-none text-[1.2em] hover:text-accent"
on:click={() => dialog.close()}
>
<CloseIcon width="0.8em" />
</button>
</dialog>
<style>
@keyframes zoom {
from { transform: scale(0.95); }
to { transform: scale(1); }
}
</style>

View File

@ -2,7 +2,7 @@
export let label: string = "";
</script>
<div class="relative flex flex-row w-full min-h-[300px] mt-5 mb-5">
<div id={label} class="relative flex flex-row w-full min-h-[300px] mt-5 mb-25">
<!-- Sticky/Sliding Label -->
<div class="hidden md:flex flex-col items-center mr-6">
<div class="sticky top-24 left-0 z-10">

View File

@ -0,0 +1,15 @@
<script lang="ts">
export let value: number = 0; // 0 to 100
</script>
<div class="w-full mt-3">
<div class="flex justify-between mb-1">
<span class="text-sm font-medium text-gray-400">{value}%</span>
</div>
<div class="w-full bg-gray-800 rounded-full h-5">
<div
class="bg-orange-400 h-5 rounded-full transition-all duration-500"
style="width: {value}%"
></div>
</div>
</div>

View File

@ -5,6 +5,9 @@
import Loading from '$lib/components/Loading.svelte';
import Section from '$lib/components/Section.svelte';
import Card from '$lib/components/Cards/Card.svelte';
import FlexGallery from "$lib/components/FlexGallery.svelte";
import SkillProgress from "$lib/components/SkillProgress.svelte";
import Timeline from './timeline.svelte';
</script>
{#await getJson('/json/me.json')}
@ -33,6 +36,23 @@
</div>
</Card>
</Section>
<!-- SKills -->
<Section label="Skills">
<FlexGallery>
{#each info.skills as skill}
<Card headerLeft={skill.name} footer={skill.link} containerStyle="flex-1 min-w-[250px] max-w-full md:min-w-[33%] opacity-100 hover:opacity-100 hover:scale-[105%] md:opacity-70 transition-all duration-300">
{skill.about}
<SkillProgress value={skill.competency} />
</Card>
{/each}
</FlexGallery>
</Section>
<Section label="Experience">
<Timeline timelineData={info.experience} />
</Section>
{:catch}
<div style="display: none;">
{toasts.add({

View File

@ -1,63 +1,67 @@
<script lang="ts">
export let timelineData: any;
import Timeline from '$lib/components/timeline/Timeline.svelte';
import TimelineItem from '$lib/components/timeline/TimelineItem.svelte';
import TimelineSeparator from '$lib/components/timeline/TimelineSeparator.svelte';
import TimelineDot from '$lib/components/timeline/TimelineDot.svelte';
import TimelineConnector from '$lib/components/timeline/TimelineConnector.svelte';
import TimelineContent from '$lib/components/timeline/TimelineContent.svelte';
import TimelineOppositeContent from '$lib/components/timeline/TimelineOppositeContent.svelte';
import Timeline from '$lib/components/timeline/Timeline.svelte';
import TimelineItem from '$lib/components/timeline/TimelineItem.svelte';
import TimelineSeparator from '$lib/components/timeline/TimelineSeparator.svelte';
import TimelineDot from '$lib/components/timeline/TimelineDot.svelte';
import TimelineConnector from '$lib/components/timeline/TimelineConnector.svelte';
import TimelineContent from '$lib/components/timeline/TimelineContent.svelte';
import TimelineOppositeContent from '$lib/components/timeline/TimelineOppositeContent.svelte';
</script>
<Timeline
position="alternate"
style={`
position="alternate"
style={`
border-radius: 3%;
padding: 1rem;
`}
>
{#each timelineData as item}
<TimelineItem>
<TimelineOppositeContent slot="opposite-content">
<p class="oposite-content-title">{item.duration}</p>
</TimelineOppositeContent>
{#each timelineData as item}
<TimelineItem>
<TimelineOppositeContent slot="opposite-content">
<p class="oposite-content-title">{item.duration}</p>
</TimelineOppositeContent>
<TimelineSeparator>
{#if item.duration.includes('Present') || !item.duration.includes('-')}
<div class="elementToFadeInAndOut">
<TimelineDot style={`background-color: var(--link); border-color: var(--accent);`} />
</div>
{:else}
<TimelineDot style={`background-color: var(--link); border-color: var(--accent);`} />
{/if}
<TimelineConnector />
</TimelineSeparator>
<TimelineContent>
<h3 class="content-title">{item.title}</h3>
<p class="content-description">{@html item.description}</p>
</TimelineContent>
</TimelineItem>
{/each}
<TimelineSeparator>
{#if item.duration.includes('Present') || !item.duration.includes('-')}
<div class="elementToFadeInAndOut">
<TimelineDot
style={`background-color: var(--link); border-color: var(--accent);`}
/>
</div>
{:else}
<TimelineDot
style={`background-color: var(--link); border-color: var(--accent);`}
/>
{/if}
<TimelineConnector />
</TimelineSeparator>
<TimelineContent>
<h3 class="content-title">{item.title}</h3>
<p class="content-description">{@html item.description}</p>
</TimelineContent>
</TimelineItem>
{/each}
</Timeline>
<style>
.oposite-content-title {
margin: 0;
padding: 0;
color: var(--accent);
}
.content-title {
margin: 0;
padding: 0;
}
.oposite-content-title {
margin: 0;
padding: 0;
color: var(--accent);
}
.content-title {
margin: 0;
padding: 0;
}
.content-description {
margin: 0;
padding: 0;
margin-top: 1rem;
color: var(--fg);
font-weight: lighter;
padding: 0.5rem 0;
}
</style>
.content-description {
margin: 0;
padding: 0;
margin-top: 1rem;
color: var(--fg);
font-weight: lighter;
padding: 0.5rem 0;
}
</style>

View File

@ -5,39 +5,44 @@
"profile_photo": "/profile.jpg",
"skills": [
{
"skill": "Rust",
"name": "Rust",
"logo": "devicon-rust-plain",
"link": "https://rust-lang.org",
"usage": "Rust is a memory-safe language with zero-cost abstractions, making it ideal for embedded systems. I used Rust to build a <a href='https://git.luke-else.co.uk/luke-else/esp32_gps_display'>GPS-based speedometer</a> for my car and a <a href='https://git.luke-else.co.uk/luke-else/subnet_calculator'>Subnet Calculator</a> for university studies.",
"about": "Rust combines safety, efficiency, and clean code, making it a powerful choice for reliable software development."
"about": "Rust combines safety, efficiency, and clean code, making it a powerful choice for reliable software development.",
"competency": 70
},
{
"skill": "C++",
"name": "C++",
"logo": "devicon-cplusplus-plain",
"link": "https://cplusplus.com/",
"usage": "Since joining Thales in 2022, Ive worked on a distributed simulation system using C++, primarily with <a href='https://www.qt.io'>Qt</a> and <a href='https://github.com/ocornut/imgui'>ImGui</a> to develop customer-facing applications.",
"about": "C++ offers high-level abstractions with low-level control, making it essential for performance-critical applications."
"about": "C++ offers high-level abstractions with low-level control, making it essential for performance-critical applications.",
"competency": 80
},
{
"skill": "Git",
"name": "Git",
"logo": "devicon-git-plain",
"link": "https://git-scm.com",
"usage": "I have extensive experience with Git, including advanced features like <a href='https://www.atlassian.com/git/tutorials/advanced-overview'>branching, merging and hooks</a>. I've also set up self-hosted <a href='https://git.luke-else.co.uk/luke-else/'>Git services</a> with CI/CD automation.",
"about": "Git is an essential tool for version control, enabling efficient collaboration and streamlined code management."
"about": "Git is an essential tool for version control, enabling efficient collaboration and streamlined code management.",
"competency": 80
},
{
"skill": "Docker",
"name": "Docker",
"logo": "devicon-docker-plain",
"link": "https://docker.com",
"usage": "I use Docker and Docker Compose for containerized deployments, including hosting <a href='https://git.luke-else.co.uk/luke-else/server'>home-lab services</a> such as this <a href='https://git.luke-else.co.uk/luke-else/luke-else.co.uk'>website</a> and remote Git repositories.",
"about": "Docker simplifies deployment by packaging applications in lightweight containers, ensuring consistency across environments."
"about": "Docker simplifies deployment by packaging applications in lightweight containers, ensuring consistency across environments.",
"competency": 100
},
{
"skill": "Svelte",
"name": "Svelte",
"logo": "devicon-svelte-plain",
"link": "https://svelte.dev",
"usage": "I built <a href='https://git.luke-else.co.uk/luke-else/luke-else.co.uk'>this website</a> using Svelte and plan to explore <a href='https://github.com/tauri-apps/tauri'>Tauri</a> for building desktop apps.",
"about": "Svelte compiles to optimized JavaScript, offering a fast, efficient, and maintainable front-end development experience."
"about": "Svelte compiles to optimized JavaScript, offering a fast, efficient, and maintainable front-end development experience.",
"competency": 40
}
],
"about": "Hello! I'm an enthusiastic, dedicated software engineer passionate about backend development, networking, and embedded systems. I am currently employed at <a href='https://www.thalesgroup.com/en'>Thales UK</a> and thrive on architecting robust backend solutions, optimizing data transmission, and crafting efficient embedded software. I love tackling complex challenges, collaborating with fellow professionals, and staying up-to-date with tech trends such as my current venture in learning <a href='https://rust-lang.org'>Rust-Lang</a>.",