ui changes and cs prices
All checks were successful
Test and deploy staging / staging (push) Successful in 11m52s

This commit is contained in:
2026-09-25 00:44:06 +00:00
parent c757d0882a
commit abac077541
200 changed files with 6236 additions and 2311 deletions

View File

@@ -2,24 +2,46 @@
import { resolve } from '$app/paths';
import portrait from '$lib/assets/stan.jpg?url';
import ProgressBar from '$lib/components/ProgressBar.svelte';
import ProjectIcon from '$lib/components/ProjectIcon.svelte';
import * as Card from '$lib/components/ui/card/index.js';
import { projects } from '$lib/projects';
import ArrowRight from 'lucide-svelte/icons/arrow-right';
import ExternalLink from 'lucide-svelte/icons/external-link';
import Mail from 'lucide-svelte/icons/mail';
import BriefcaseBusiness from 'lucide-svelte/icons/briefcase-business';
import GraduationCap from 'lucide-svelte/icons/graduation-cap';
import type { PageProps } from './$types';
let { data }: PageProps = $props();
const experienceImages = import.meta.glob<string>(
'/src/lib/assets/experience/*.{webp,png,jpg,jpeg,avif,svg}',
{ eager: true, query: '?url', import: 'default' }
);
function experienceImage(filename: string) {
return (
['webp', 'png', 'jpg', 'jpeg', 'avif', 'svg']
.map((extension) => experienceImages[`/src/lib/assets/experience/${filename}.${extension}`])
.find(Boolean) ??
(filename === 'cargill'
? experienceImages[
'/src/lib/assets/experience/Cargill-Logo-R-Black-and-Leaf-Green-RGB.webp'
]
: undefined)
);
}
const experience = [
{ when: '2026–now', role: 'associate software engineer', place: 'Cargill' },
{ when: '2026–now', role: 'associate software engineer', place: 'Cargill', icon: 'cargill' },
{
when: '2021–2026',
role: 'BSc computer science · software engineering',
place: 'The Hague University of Applied Sciences'
place: 'The Hague University of Applied Sciences',
icon: 'the-hague-university'
},
{ when: '2026', role: 'software engineering intern', place: '3webapps' },
{ when: '2023', role: 'software engineering intern', place: 'h5mag' },
{ when: '2021–2023', role: 'junior IT specialist', place: 'Finance Plus' }
{ when: '2026', role: 'software engineering intern', place: '3webapps', icon: '3webapps' },
{ when: '2023', role: 'software engineering intern', place: 'h5mag', icon: 'h5mag' },
{ when: '2021–2023', role: 'junior IT specialist', place: 'Finance Plus', icon: 'finance-plus' }
] as const;
</script>
@@ -82,41 +104,61 @@
>projects <ArrowRight size={20} aria-hidden="true" /></a
>
</h2>
<ul>
<ul class="grid gap-3 sm:grid-cols-2">
{#each projects as project (project.name)}
<li class="border-b border-[var(--site-border)] text-lg">
{#if project.external}
<a
href={project.href}
rel="external"
class="flex items-center justify-between gap-4 py-4 hover:text-[var(--site-muted)]"
>
<span class="min-w-0">
<span class="block">{project.name}</span>
<span class="mt-1 block text-base text-[var(--site-muted)]">{project.subtitle}</span
<li>
<Card.Root class="h-full py-0 transition-colors hover:bg-muted/50"
><Card.Content class="p-0">
{#if project.external}
<a
href={project.href}
rel="external"
class="flex min-h-28 items-start justify-between gap-4 p-5"
>
</span><ExternalLink
size={18}
aria-hidden="true"
class="shrink-0 text-[var(--site-muted)]"
/>
</a>
{:else}
<a
href={resolve(project.href)}
class="flex items-center justify-between gap-4 py-4 hover:text-[var(--site-muted)]"
>
<span class="min-w-0">
<span class="block">{project.name}</span>
<span class="mt-1 block text-base text-[var(--site-muted)]">{project.subtitle}</span
<span class="flex min-w-0 items-start gap-3">
<span
class="mt-0.5 flex size-10 shrink-0 items-center justify-center rounded-md border border-border bg-[var(--site-surface)] text-[var(--site-muted)]"
>
<ProjectIcon name={project.name} class="size-5" />
</span>
<span class="min-w-0">
<span class="block font-medium">{project.name}</span>
<span class="mt-1 block text-base text-[var(--site-muted)]"
>{project.subtitle}</span
>
</span>
</span><ExternalLink
size={18}
aria-hidden="true"
class="shrink-0 text-[var(--site-muted)]"
/>
</a>
{:else}
<a
href={resolve(project.href)}
class="flex min-h-28 items-start justify-between gap-4 p-5"
>
</span><ArrowRight
size={18}
aria-hidden="true"
class="shrink-0 text-[var(--site-muted)]"
/>
</a>
{/if}
<span class="flex min-w-0 items-start gap-3">
<span
class="mt-0.5 flex size-10 shrink-0 items-center justify-center rounded-md border border-border bg-[var(--site-surface)] text-[var(--site-muted)]"
>
<ProjectIcon name={project.name} class="size-5" />
</span>
<span class="min-w-0">
<span class="block font-medium">{project.name}</span>
<span class="mt-1 block text-base text-[var(--site-muted)]"
>{project.subtitle}</span
>
</span>
</span><ArrowRight
size={18}
aria-hidden="true"
class="shrink-0 text-[var(--site-muted)]"
/>
</a>
{/if}
</Card.Content></Card.Root
>
</li>
{/each}
</ul>
@@ -135,37 +177,41 @@
<li class="border-b border-[var(--site-border)] text-lg">
<a
href={resolve('/lists/[slug]', { slug: list.slug })}
class="block py-4 hover:text-[var(--site-muted)]"
class={list.isProgress
? 'grid grid-cols-[minmax(0,1fr)_8rem_auto] items-center gap-3 py-4 hover:text-[var(--site-muted)]'
: 'flex items-center justify-between gap-3 py-4 hover:text-[var(--site-muted)]'}
>
<span class="flex flex-wrap items-center justify-between gap-x-6 gap-y-1">
<span class="flex items-center gap-3">
{#if list.pictureUrl}<img
src={list.pictureUrl}
alt=""
loading="lazy"
width="40"
height="40"
class="h-10 w-10 rounded bg-[var(--site-surface)] object-cover"
/>{/if}
<span>{list.name}</span>
</span>
<span class="inline-flex items-center gap-1 text-base text-[var(--site-muted)]">
{#if list.isProgress && data.user}
{list.total ? Math.round((list.checked / list.total) * 100) : 0}% · {list.checked}/{list.total}
{:else}
{list.total} {list.total === 1 ? 'item' : 'items'}
{/if}
<ArrowRight size={16} aria-hidden="true" />
</span>
<span class="flex min-w-0 items-center gap-3">
{#if list.pictureUrl}<img
src={list.pictureUrl}
alt=""
loading="lazy"
width="40"
height="40"
class="h-10 w-10 rounded bg-[var(--site-surface)] object-cover"
/>{/if}
<span class="truncate">{list.name}</span>
</span>
{#if list.isProgress}<span class="mt-3 block"
{#if list.isProgress}
<span class="block w-32"
><ProgressBar
value={list.checked}
max={list.total}
label={`Progress on ${list.name}`}
small
/></span
>{/if}
>
{/if}
<span
class="inline-flex min-w-16 items-center justify-end gap-1 whitespace-nowrap text-base text-[var(--site-muted)]"
>
{#if list.isProgress && data.user}
{list.total ? Math.round((list.checked / list.total) * 100) : 0}%
{:else}
{list.total}
{/if}
<ArrowRight size={16} aria-hidden="true" />
</span>
</a>
</li>
{/each}
@@ -176,14 +222,35 @@
<h2 id="experience-heading" class="mb-4 text-2xl font-semibold tracking-tight">experience</h2>
<ol>
{#each experience as item (item.when + item.place)}
{@const image = experienceImage(item.icon)}
<li
class="grid gap-1 border-t border-[var(--site-border)] py-4 sm:grid-cols-[minmax(0,1fr)_130px] sm:gap-6"
class="grid grid-cols-[3rem_minmax(0,1fr)] gap-x-4 gap-y-1 border-t border-[var(--site-border)] py-4 sm:grid-cols-[3rem_minmax(0,1fr)_130px]"
>
<span
class="row-span-2 flex size-12 items-center justify-center overflow-hidden rounded-md border border-border bg-[var(--site-surface)] text-muted-foreground sm:row-span-1"
>
{#if image}
<img
src={image}
alt=""
width="48"
height="48"
loading="lazy"
class="size-full object-cover"
/>
{:else if item.icon === 'the-hague-university'}
<GraduationCap class="size-5" aria-hidden="true" />
{:else}
<BriefcaseBusiness class="size-5" aria-hidden="true" />
{/if}
</span>
<div class="min-w-0">
<h3 class="font-medium">{item.role}</h3>
<p class="mt-1 text-base text-[var(--site-muted)]">{item.place}</p>
</div>
<span class="text-base text-[var(--site-muted)] sm:text-right">{item.when}</span>
<span class="col-start-2 text-base text-[var(--site-muted)] sm:col-start-3 sm:text-right"
>{item.when}</span
>
</li>
{/each}
</ol>