```
All checks were successful
Build and Push Docker Image / build (push) Successful in 29s

Add resume components and job data for SvelteKit app

- Added `PageHeader`, `JobCard`, `Card`, and `Badge` components
- Integrated job data for Quantified Impacts and Rannes.dev
- Updated layout and page structure with new components
- Included LinkedIn profile image and social links
- Installed `@lucide/svelte` for icons
- Removed unused `$lib/index.ts`
```
This commit is contained in:
christian 2025-05-06 00:10:56 +02:00
parent 298fbc50d5
commit 6f8a5f7a33
14 changed files with 258 additions and 55 deletions

View File

@ -39,5 +39,8 @@
"onlyBuiltDependencies": [
"esbuild"
]
},
"dependencies": {
"@lucide/svelte": "^0.507.0"
}
}

113
pnpm-lock.yaml generated
View File

@ -7,6 +7,10 @@ settings:
importers:
.:
dependencies:
'@lucide/svelte':
specifier: ^0.507.0
version: 0.507.0(svelte@5.28.2)
devDependencies:
'@eslint/compat':
specifier: ^1.2.5
@ -64,7 +68,7 @@ importers:
version: 5.8.3
typescript-eslint:
specifier: ^8.20.0
version: 8.31.1(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3)
version: 8.32.0(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3)
vite:
specifier: ^6.2.6
version: 6.3.5(jiti@2.4.2)(lightningcss@1.29.2)
@ -310,6 +314,11 @@ packages:
'@jridgewell/trace-mapping@0.3.25':
resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==}
'@lucide/svelte@0.507.0':
resolution: {integrity: sha512-kXIg/2IHEo1bAwZG94fjA9O6+E3Sv5aQrW2yyPf4JvCYIUIF8DGLIQI4vfjoUyNq2dEX4cI33pZarzGOHr0npg==}
peerDependencies:
svelte: ^5
'@modelcontextprotocol/sdk@1.11.0':
resolution: {integrity: sha512-k/1pb70eD638anoi0e8wUGAlbMJXyvdV4p62Ko+EZ7eBe1xMx8Uhak1R5DgfoofsK5IBBnRwsYGTaLZl+6/+RQ==}
engines: {node: '>=18'}
@ -606,51 +615,51 @@ packages:
'@types/resolve@1.20.2':
resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==}
'@typescript-eslint/eslint-plugin@8.31.1':
resolution: {integrity: sha512-oUlH4h1ABavI4F0Xnl8/fOtML/eu8nI2A1nYd+f+55XI0BLu+RIqKoCiZKNo6DtqZBEQm5aNKA20G3Z5w3R6GQ==}
'@typescript-eslint/eslint-plugin@8.32.0':
resolution: {integrity: sha512-/jU9ettcntkBFmWUzzGgsClEi2ZFiikMX5eEQsmxIAWMOn4H3D4rvHssstmAHGVvrYnaMqdWWWg0b5M6IN/MTQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
'@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <5.9.0'
'@typescript-eslint/parser@8.31.1':
resolution: {integrity: sha512-oU/OtYVydhXnumd0BobL9rkJg7wFJ9bFFPmSmB/bf/XWN85hlViji59ko6bSKBXyseT9V8l+CN1nwmlbiN0G7Q==}
'@typescript-eslint/parser@8.32.0':
resolution: {integrity: sha512-B2MdzyWxCE2+SqiZHAjPphft+/2x2FlO9YBx7eKE1BCb+rqBlQdhtAEhzIEdozHd55DXPmxBdpMygFJjfjjA9A==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <5.9.0'
'@typescript-eslint/scope-manager@8.31.1':
resolution: {integrity: sha512-BMNLOElPxrtNQMIsFHE+3P0Yf1z0dJqV9zLdDxN/xLlWMlXK/ApEsVEKzpizg9oal8bAT5Sc7+ocal7AC1HCVw==}
'@typescript-eslint/scope-manager@8.32.0':
resolution: {integrity: sha512-jc/4IxGNedXkmG4mx4nJTILb6TMjL66D41vyeaPWvDUmeYQzF3lKtN15WsAeTr65ce4mPxwopPSo1yUUAWw0hQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@typescript-eslint/type-utils@8.31.1':
resolution: {integrity: sha512-fNaT/m9n0+dpSp8G/iOQ05GoHYXbxw81x+yvr7TArTuZuCA6VVKbqWYVZrV5dVagpDTtj/O8k5HBEE/p/HM5LA==}
'@typescript-eslint/type-utils@8.32.0':
resolution: {integrity: sha512-t2vouuYQKEKSLtJaa5bB4jHeha2HJczQ6E5IXPDPgIty9EqcJxpr1QHQ86YyIPwDwxvUmLfP2YADQ5ZY4qddZg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <5.9.0'
'@typescript-eslint/types@8.31.1':
resolution: {integrity: sha512-SfepaEFUDQYRoA70DD9GtytljBePSj17qPxFHA/h3eg6lPTqGJ5mWOtbXCk1YrVU1cTJRd14nhaXWFu0l2troQ==}
'@typescript-eslint/types@8.32.0':
resolution: {integrity: sha512-O5Id6tGadAZEMThM6L9HmVf5hQUXNSxLVKeGJYWNhhVseps/0LddMkp7//VDkzwJ69lPL0UmZdcZwggj9akJaA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@typescript-eslint/typescript-estree@8.31.1':
resolution: {integrity: sha512-kaA0ueLe2v7KunYOyWYtlf/QhhZb7+qh4Yw6Ni5kgukMIG+iP773tjgBiLWIXYumWCwEq3nLW+TUywEp8uEeag==}
'@typescript-eslint/typescript-estree@8.32.0':
resolution: {integrity: sha512-pU9VD7anSCOIoBFnhTGfOzlVFQIA1XXiQpH/CezqOBaDppRwTglJzCC6fUQGpfwey4T183NKhF1/mfatYmjRqQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
typescript: '>=4.8.4 <5.9.0'
'@typescript-eslint/utils@8.31.1':
resolution: {integrity: sha512-2DSI4SNfF5T4oRveQ4nUrSjUqjMND0nLq9rEkz0gfGr3tg0S5KB6DhwR+WZPCjzkZl3cH+4x2ce3EsL50FubjQ==}
'@typescript-eslint/utils@8.32.0':
resolution: {integrity: sha512-8S9hXau6nQ/sYVtC3D6ISIDoJzS1NsCK+gluVhLN2YkBPX+/1wkwyUiDKnxRh15579WoOIyVWnoyIf3yGI9REw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <5.9.0'
'@typescript-eslint/visitor-keys@8.31.1':
resolution: {integrity: sha512-I+/rgqOVBn6f0o7NDTmAPWWC6NuqhV174lfYvAm9fUaWeiefLdux9/YI3/nLugEn9L8fcSi0XmpKi/r5u0nmpw==}
'@typescript-eslint/visitor-keys@8.32.0':
resolution: {integrity: sha512-1rYQTCLFFzOI5Nl0c8LUpJT8HxpwVRn9E4CkMsYfuN6ctmQqExjSTzzSk0Tz2apmXy7WU6/6fyaZVVA/thPN+w==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
accepts@2.0.0:
@ -1635,8 +1644,8 @@ packages:
resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==}
engines: {node: '>= 0.6'}
typescript-eslint@8.31.1:
resolution: {integrity: sha512-j6DsEotD/fH39qKzXTQRwYYWlt7D+0HmfpOK+DVhwJOFLcdmn92hq3mBb7HlKJHbjjI/gTOqEcc9d6JfpFf/VA==}
typescript-eslint@8.32.0:
resolution: {integrity: sha512-UMq2kxdXCzinFFPsXc9o2ozIpYCCOiEC46MG3yEh5Vipq6BO27otTtEBZA1fQ66DulEUgE97ucQ/3YY66CPg0A==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: ^8.57.0 || ^9.0.0
@ -1900,6 +1909,10 @@ snapshots:
'@jridgewell/resolve-uri': 3.1.2
'@jridgewell/sourcemap-codec': 1.5.0
'@lucide/svelte@0.507.0(svelte@5.28.2)':
dependencies:
svelte: 5.28.2
'@modelcontextprotocol/sdk@1.11.0':
dependencies:
content-type: 1.0.5
@ -2157,14 +2170,14 @@ snapshots:
'@types/resolve@1.20.2': {}
'@typescript-eslint/eslint-plugin@8.31.1(@typescript-eslint/parser@8.31.1(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3))(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3)':
'@typescript-eslint/eslint-plugin@8.32.0(@typescript-eslint/parser@8.32.0(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3))(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3)':
dependencies:
'@eslint-community/regexpp': 4.12.1
'@typescript-eslint/parser': 8.31.1(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3)
'@typescript-eslint/scope-manager': 8.31.1
'@typescript-eslint/type-utils': 8.31.1(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3)
'@typescript-eslint/utils': 8.31.1(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3)
'@typescript-eslint/visitor-keys': 8.31.1
'@typescript-eslint/parser': 8.32.0(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3)
'@typescript-eslint/scope-manager': 8.32.0
'@typescript-eslint/type-utils': 8.32.0(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3)
'@typescript-eslint/utils': 8.32.0(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3)
'@typescript-eslint/visitor-keys': 8.32.0
eslint: 9.26.0(jiti@2.4.2)
graphemer: 1.4.0
ignore: 5.3.2
@ -2174,27 +2187,27 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@typescript-eslint/parser@8.31.1(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3)':
'@typescript-eslint/parser@8.32.0(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3)':
dependencies:
'@typescript-eslint/scope-manager': 8.31.1
'@typescript-eslint/types': 8.31.1
'@typescript-eslint/typescript-estree': 8.31.1(typescript@5.8.3)
'@typescript-eslint/visitor-keys': 8.31.1
'@typescript-eslint/scope-manager': 8.32.0
'@typescript-eslint/types': 8.32.0
'@typescript-eslint/typescript-estree': 8.32.0(typescript@5.8.3)
'@typescript-eslint/visitor-keys': 8.32.0
debug: 4.4.0
eslint: 9.26.0(jiti@2.4.2)
typescript: 5.8.3
transitivePeerDependencies:
- supports-color
'@typescript-eslint/scope-manager@8.31.1':
'@typescript-eslint/scope-manager@8.32.0':
dependencies:
'@typescript-eslint/types': 8.31.1
'@typescript-eslint/visitor-keys': 8.31.1
'@typescript-eslint/types': 8.32.0
'@typescript-eslint/visitor-keys': 8.32.0
'@typescript-eslint/type-utils@8.31.1(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3)':
'@typescript-eslint/type-utils@8.32.0(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3)':
dependencies:
'@typescript-eslint/typescript-estree': 8.31.1(typescript@5.8.3)
'@typescript-eslint/utils': 8.31.1(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3)
'@typescript-eslint/typescript-estree': 8.32.0(typescript@5.8.3)
'@typescript-eslint/utils': 8.32.0(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3)
debug: 4.4.0
eslint: 9.26.0(jiti@2.4.2)
ts-api-utils: 2.1.0(typescript@5.8.3)
@ -2202,12 +2215,12 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@typescript-eslint/types@8.31.1': {}
'@typescript-eslint/types@8.32.0': {}
'@typescript-eslint/typescript-estree@8.31.1(typescript@5.8.3)':
'@typescript-eslint/typescript-estree@8.32.0(typescript@5.8.3)':
dependencies:
'@typescript-eslint/types': 8.31.1
'@typescript-eslint/visitor-keys': 8.31.1
'@typescript-eslint/types': 8.32.0
'@typescript-eslint/visitor-keys': 8.32.0
debug: 4.4.0
fast-glob: 3.3.3
is-glob: 4.0.3
@ -2218,20 +2231,20 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@typescript-eslint/utils@8.31.1(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3)':
'@typescript-eslint/utils@8.32.0(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3)':
dependencies:
'@eslint-community/eslint-utils': 4.7.0(eslint@9.26.0(jiti@2.4.2))
'@typescript-eslint/scope-manager': 8.31.1
'@typescript-eslint/types': 8.31.1
'@typescript-eslint/typescript-estree': 8.31.1(typescript@5.8.3)
'@typescript-eslint/scope-manager': 8.32.0
'@typescript-eslint/types': 8.32.0
'@typescript-eslint/typescript-estree': 8.32.0(typescript@5.8.3)
eslint: 9.26.0(jiti@2.4.2)
typescript: 5.8.3
transitivePeerDependencies:
- supports-color
'@typescript-eslint/visitor-keys@8.31.1':
'@typescript-eslint/visitor-keys@8.32.0':
dependencies:
'@typescript-eslint/types': 8.31.1
'@typescript-eslint/types': 8.32.0
eslint-visitor-keys: 4.2.0
accepts@2.0.0:
@ -3183,11 +3196,11 @@ snapshots:
media-typer: 1.1.0
mime-types: 3.0.1
typescript-eslint@8.31.1(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3):
typescript-eslint@8.32.0(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3):
dependencies:
'@typescript-eslint/eslint-plugin': 8.31.1(@typescript-eslint/parser@8.31.1(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3))(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3)
'@typescript-eslint/parser': 8.31.1(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3)
'@typescript-eslint/utils': 8.31.1(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3)
'@typescript-eslint/eslint-plugin': 8.32.0(@typescript-eslint/parser@8.32.0(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3))(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3)
'@typescript-eslint/parser': 8.32.0(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3)
'@typescript-eslint/utils': 8.32.0(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3)
eslint: 9.26.0(jiti@2.4.2)
typescript: 5.8.3
transitivePeerDependencies:

View File

@ -6,7 +6,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1" />
%sveltekit.head%
</head>
<body data-sveltekit-preload-data="hover">
<body data-sveltekit-preload-data="hover" class="bg-gray-100">
<div style="display: contents">%sveltekit.body%</div>
</body>
</html>

View File

@ -1 +0,0 @@
// place files you want to import through the `$lib` alias in this folder.

BIN
src/lib/linkedin.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

View File

@ -4,4 +4,6 @@
let { children } = $props();
</script>
{@render children()}
<div class="mx-4 my-8">
{@render children()}
</div>

View File

@ -1,2 +1,26 @@
<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 lang="ts">
import JobCard from './JobCard.svelte';
import PageHeader from './PageHeader.svelte';
import { qiDescription, qiAccomplish } from './qiData';
import { rannesDescription, rannesAccomplish } from './rannesDevData';
</script>
<div class="flex flex-col gap-4">
<PageHeader />
<JobCard
title="Full Stack Developer"
company="Quantified Impacts"
start="Aug. 2024"
end="Present"
jobDescription={qiDescription}
accomplishments={qiAccomplish}
/>
<JobCard
title="Owner"
company="Rannes.dev"
start="Dec. 2024"
end="Present"
jobDescription={rannesDescription}
accomplishments={rannesAccomplish}
/>
</div>

7
src/routes/Badge.svelte Normal file
View File

@ -0,0 +1,7 @@
<script lang="ts">
let { children } = $props();
</script>
<div class="rounded-full bg-gray-200 px-2 py-1 text-sm text-gray-600">
{@render children()}
</div>

7
src/routes/Card.svelte Normal file
View File

@ -0,0 +1,7 @@
<script lang="ts">
let { children } = $props();
</script>
<div class="rounded-md bg-white px-8 py-6 shadow-md">
{@render children()}
</div>

40
src/routes/JobCard.svelte Normal file
View File

@ -0,0 +1,40 @@
<script lang="ts">
import Badge from './Badge.svelte';
import Card from './Card.svelte';
import type { Accomplishment } from './types';
type ComponentProps = {
title: string;
company: string;
start: string;
end: string;
jobDescription: string;
accomplishments: Accomplishment[];
};
let { title, company, start, end, jobDescription, accomplishments }: ComponentProps = $props();
</script>
<Card>
<div class="flex items-center gap-4">
<h2 class="mb-2 text-2xl tracking-tight">{title} @ {company}</h2>
<p class="text-sm text-slate-400">{start} - {end}</p>
</div>
<h3 class="mt-6 text-2xl">Job Description</h3>
<p class="mt-4">
{jobDescription}
</p>
<h3 class="mt-6 text-2xl">Accomplishments</h3>
<ul class="mt-4 list-inside list-disc">
{#each accomplishments as accomplishment, i (i)}
<li class="mt-4 text-xl">
<span>{accomplishment.title}</span>
<p class="ml-5 text-base">{accomplishment.description}</p>
<div class="mt-2 ml-5 flex gap-2">
{#each accomplishment.tags as tag, i (`${tag}-${i}`)}
<Badge>{tag}</Badge>
{/each}
</div>
</li>
{/each}
</ul>
</Card>

View File

@ -0,0 +1,35 @@
<script lang="ts">
import { AtSign, Github, Globe, Linkedin } from '@lucide/svelte';
import Card from './Card.svelte';
import linkedInImg from '$lib/linkedin.jpg';
</script>
<Card>
<div class="flex justify-between">
<div class="my-4 flex flex-col justify-between gap-2">
<div>
<h1 class="text-4xl tracking-tight">Developer Resume For Christian Rannes</h1>
<h2 class="text-xl text-slate-400">
Full Stack Developer Passionate about infrastructure, DevOps and Developer Experience
</h2>
</div>
<div class="flex gap-2">
<a href="https://www.linkedin.com/in/christian-rannes/">
<Linkedin />
</a>
<a href="mailto:christian@rannes.dev">
<AtSign />
</a>
<a href="http://rannes.dev">
<Globe />
</a>
<a href="https://github.com/ChrQR">
<Github />
</a>
</div>
</div>
<div class="flex min-w-44 items-center">
<img src={linkedInImg} alt="a happy guy" class="h-44 w-44 rounded-full shadow-sm" />
</div>
</div>
</Card>

49
src/routes/qiData.ts Normal file
View File

@ -0,0 +1,49 @@
import type { Accomplishment } from './types';
export const qiDescription =
'As a Full Stack Developer at Quantified Impacts I have touched every part of our code, from infrastructure and CI/CD to our Frontend in react/typescript and our backend in Django/Python. I am fast at learning new things, and now to tackle challenges, and come up with fast, durable and scaleable solutions. When we need to research or develop POCs for new features, I am often assigned the lead for these tasks. ';
export const qiAccomplish: Accomplishment[] = [
{
title: 'Planned and facilitated maturation of infrastructure.',
description:
'When I started with Quantified Impacts we had our application running in two container apps, and a postgresql db, which was all exposed to the world wide web. I planned out our new infrastructure and hired a consultant to do the initial implementation in terraform, securing all services in virtual networks, connected with private end-points and accesible only through Azure Frontdoor. This is all declared using Terraform, so we can easily spin up another environment.',
tags: ['Terraform', 'Azure']
},
{
title: 'Implemented CI/CD Pipeline',
description:
"As we're a small team that wants to get our newest features out to our users as fast as possible, I set up a build and release pipeline using github actions.",
tags: ['Github Actions', 'Azure']
},
{
title: 'External API v1',
description:
'I built our initial external api as an application in our Django backend. It is used by our largest clients, who are making hundreds of thousands requests overnight. The API has full test coverage of unit tests and End2End tests written i pytest.',
tags: ['Python', 'Django', 'REST']
},
{
title: 'Redesign of our datamodels and database',
description:
'In January started planning a big rewrite of our backend and data models, to facilitate millions of carbon footprint calculations, storing calculation parameters, history and changelog for all objects.',
tags: ['Postgresql', 'Django', 'Python']
},
{
title: 'Migration of frontend to React Router 7 framework and SSR',
description:
'After a big rewrite of our backend, we decided to move to the newest version of React Router and use it as framework, which required an almost full rewrite of our frontend. While rewriting the frontend we also adopted Shadcn for ui components and tailwindcss for styling.',
tags: ['React Router', 'React', 'typescript', 'Tailwind']
},
{
title: 'External API v2',
description:
'The second iteration of our external API is written in FastAPI for fast development speed, and better performance compared to Django.',
tags: ['FastAPI', 'Pydantic', 'Python', 'REST']
},
{
title: 'Data fetching service from OKOBAUDAT',
description:
'A container job (Cron job) that fetches thousands of EPD reports from OKOBAUDAT every night, transform them to fit our data models, and inserts or update them in our database. The service is written in Golang.',
tags: ['Golang', 'Azure', 'Cron Jobs']
}
];

View File

@ -0,0 +1,19 @@
import type { Accomplishment } from './types';
export const rannesDescription =
'As I got a request for a web site, and another for a code review I took the opportunity to start a little consultant business. I develop solutions and web sites for restaurants, and provide technical consulting for early stage start ups. My production applications are deployed to a k3s cluster that are running on a couple of Hetzner vps.';
export const rannesAccomplish: Accomplishment[] = [
{
title: 'Developed, Deployed and maintaining Calma.dk',
description:
'The web page is developed in Svelte with integrated CMS (Sanity.io) which allows the client to customize all text, and menus on the page. I also wrote a program in Golang which parses their winelist from an excel sheet (their stock take list), and uploads it to a s3 bucket from where its served to the user on the web page. This enables the client to make instant changes to their website, including their winelist. The page is built mobile first, and scales for all devices. It is deployed to my k3s cluster in hetzner',
tags: ['Svelte', 'Sveltekit', 'AWS', 'k3s', 'Object Storage', 'CMS']
},
{
title: 'Developed, deployed and maintaining Sauerwine.dk',
description:
'The web page is developed in Svelte and integrated with CMS (Sanity.io) so the client can change all text content on the web page. It is deployed to my k3s cluster in hetzner.',
tags: ['Svelte', 'Sveltekit', 'k3s', 'CMS']
}
];

5
src/routes/types.ts Normal file
View File

@ -0,0 +1,5 @@
export type Accomplishment = {
title: string;
description: string;
tags: string[];
};