feat: add project pages

This commit is contained in:
Alexander Daichendt 2023-09-27 23:36:46 +02:00
parent 5fc58fd0bc
commit d41a23cfcf
16 changed files with 171 additions and 28 deletions

View file

@ -1,7 +1,12 @@
{ {
"name": "myblog", "name": "daichendt.one",
"version": "0.0.1", "version": "1.0.0",
"license": "MIT", "license": "MIT",
"author": {
"email": "me@daichendt.one",
"name": "Alex Daichendt"
},
"type": "module",
"scripts": { "scripts": {
"dev": "vite dev", "dev": "vite dev",
"build": "vite build", "build": "vite build",
@ -43,7 +48,6 @@
"vite": "^4.0.3", "vite": "^4.0.3",
"vite-imagetools": "^4.0.12" "vite-imagetools": "^4.0.12"
}, },
"type": "module",
"dependencies": { "dependencies": {
"@fontsource/ubuntu-mono": "^4.5.11", "@fontsource/ubuntu-mono": "^4.5.11",
"@mdi/js": "^7.1.96", "@mdi/js": "^7.1.96",

View file

@ -5,6 +5,7 @@
const NAV_ITEMS = [ const NAV_ITEMS = [
{ href: '/', label: 'Home' }, { href: '/', label: 'Home' },
{ href: '/blog', label: 'Blog' }, { href: '/blog', label: 'Blog' },
{ href: '/projects', label: 'Projects' },
{ href: '/contact', label: 'Contact' }, { href: '/contact', label: 'Contact' },
]; ];
</script> </script>

View file

@ -30,10 +30,11 @@
{...props} {...props}
{href} {href}
> >
<span class="text"><slot /></span>
{#if !disableIcon && !internal} {#if !disableIcon && !internal}
<Icon path={internal ? mdiChevronRight : mdiLinkVariant} size="1rem" /> <Icon path={internal ? mdiChevronRight : mdiLinkVariant} size="1rem" />
{/if} {/if}
<span class="text"><slot /></span>
</a><style> </a><style>
a { a {
color: var(--special-color); color: var(--special-color);

View file

@ -33,13 +33,19 @@
<SEO {title} {description} {keywords} /> <SEO {title} {description} {keywords} />
<h1>{title}</h1> <h1>{title}</h1>
{#if updated || created}
<aside role="note"> <aside role="note">
{#if updated} {#if updated}
<Icon path={mdiPencil} size="0.8rem" /> updated {new Date(updated).toLocaleDateString('en-GB')}; <Icon path={mdiPencil} size="0.8rem" /> updated {new Date(updated).toLocaleDateString(
'en-GB',
)};
{/if} {/if}
{#if created}
<Icon path={mdiCalendar} size="0.8rem" /> created <Icon path={mdiCalendar} size="0.8rem" /> created
{new Date(created).toLocaleDateString('en-GB')} {new Date(created).toLocaleDateString('en-GB')}
{/if}
</aside> </aside>
{/if}
<Divider /> <Divider />
<slot /> <slot />

View file

View file

@ -10,6 +10,17 @@ export interface BlogPostFrontmatter {
export interface BlogPostMeta extends BlogPostFrontmatter { export interface BlogPostMeta extends BlogPostFrontmatter {
href: string; href: string;
} }
export interface ProjectsFrontmatter {
title: string;
description: string;
keywords: string[];
inProgress: boolean;
}
export interface ProjectMeta extends ProjectsFrontmatter {
href: string;
}
export interface Skill { export interface Skill {
name: string; name: string;
years: number; years: number;

View file

@ -23,7 +23,7 @@
} }
:global(.container) { :global(.container) {
max-width: 70rem; max-width: 50rem;
margin: 0 auto; margin: 0 auto;
padding: 0 1rem; padding: 0 1rem;
overflow-x: hidden; overflow-x: hidden;

View file

@ -60,12 +60,18 @@
<p>I am a software engineer, Linux enthusiast and a friend of lightweight, resilient systems.</p> <p>I am a software engineer, Linux enthusiast and a friend of lightweight, resilient systems.</p>
<p> <p>
Programming has been a hobby of mine since my teens. Been working on countless projects for My journey in the tech world has been a dynamic one. I've immersed myself in countless projects
various games. For a few years now I am maintaining a small homelab, which got me into DevOps/SRE. spanning various video games and, for the past few years, have been maintaining a small homelab,
I am a privacy enthusiast and advocate for non-invasive software. Sometimes, I build slick which ignited my passion for DevOps / SRE. I am a privacy enthusiast and advocate for non-invasive
websites that do not load megabytes of data and try to follow best-practices. Currently, I am software. Occasionally, I channel my creativity into building sleek web applications that
working on my Masters degree in computer science at <Link href="https://www.tum.de/">TUM</Link>. prioritize efficiency and adhere to web standards and best practices.
</p> </p>
<p>
Currently, I'm pursuing a Master's degree in computer science at <Link href="https://www.tum.de/"
>TUM</Link
>, where I successfully contribute to numerous research papers.
</p>
<h2>Skills</h2> <h2>Skills</h2>
<ul> <ul>

View file

@ -2,7 +2,7 @@ export async function load() {
return { return {
seo: { seo: {
title: 'Home', title: 'Home',
description: 'Alex Daichendt"s website, blog, and yard of stuffs and things of modern tech.', description: 'Alex Daichendt"s website, blog, and collection of thoughts on modern tech.',
}, },
}; };
} }

View file

@ -0,0 +1,22 @@
import type { ProjectMeta, ProjectsFrontmatter } from '$lib/utils/types';
import type { PageServerLoad } from './$types';
const removeExtension = (path: string) => path.replace(/\.[^.]*$/g, '').replace('/+page', '');
export const load: PageServerLoad = async () => {
const modulesSVX = import.meta.glob('./**/*.svx');
const modulesMD = import.meta.glob('./**/*.md');
const modules = { ...modulesMD, ...modulesSVX };
const projects: ProjectMeta[] = [];
const resolved = (await Promise.all(Object.values(modules).map((f) => f()))) as {
metadata: ProjectsFrontmatter;
}[];
resolved.forEach((file, index) => {
const path = Object.keys(modules)[index];
const { metadata } = file;
projects.push({ ...metadata, href: `projects/${removeExtension(path)}` });
});
return { projects };
};

View file

@ -0,0 +1,22 @@
<script lang="ts">
import Link from '$components/Link.svelte';
import ListItem from '$components/ListItem.svelte';
import Seo from '$components/SEO.svelte';
import type { PageData } from './$types';
export let data: PageData;
$: projects = data.projects;
</script>
<Seo />
<h1>Projects</h1>
<p>Detailed descriptions of my contributions to various projects.</p>
<ul>
{#each projects as project}
<ListItem>
<Link href={project.href}>{project.title}</Link>
</ListItem>
{/each}
</ul>

View file

@ -0,0 +1,11 @@
import type { PageLoad } from './$types';
export const load: PageLoad = ({ data }) => {
return {
projects: data.projects,
seo: {
title: 'Projects',
description: 'Detailed descriptions of projects created by Alex Daichendt',
},
};
};

View file

@ -0,0 +1,61 @@
---
title: 'GW2 Gear Optimizer'
description: 'The Gear Optimizer helps Guild Wars 2 players find optimal builds for fractals, raids, and strike missions.'
keywords:
- gw2
- guild wars 2
- optimizer
layout: blog
---
<script>
import overview from "./images/gear-optimizer.png?default"
import Image from "$components/Image.svelte"
</script>
## TL;DR
{description}
- Demo / live site: [https://optimizer.discretize.eu](https://optimizer.discretize.eu)
- Code: [Github](https://github.com/discretize/discretize-gear-optimizer)
I made signifcant contributions to the frontend as well as to the calculation core by rewriting it in Rust and implementing threading.
Furthermore, I worked closely with and coordinated a small team of a few developers from all over the world ([see here](https://github.com/discretize/discretize-gear-optimizer/graphs/contributors)) to improve the project further.
<Image meta={overview} />
## Description
Interesting features for players of the video game:
- find optimal builds based on various parameters
- build templates with extensive sensible defaults that are used by players
- support for different game modes with different balancing
- Uptime input for conditional buffs
- keyboard shortcuts
- custom arbitrary modifier input to allow simulating theoretical balancing
- infusion helper: calculates the cheapest way to acquire n agony resistance
- input condition distribution
- displays the results just like in game
- share settings and results with a single link
## Most Significant Contributions
- I rewrote the frontend from scratch utilizing modern JS tooling
-> the old optimizer consisted out of one 10k LoC HTML file and an equally large js file; bundled with gulp and jquery ...
- ported the calculation core to Rust; refactored the combination generation code to support multi-threading
-> added some heuristics to reduce the amount of combinations
- state compression algorithm based on a schema so that players can share links to their builds without a server storing data
## Technical Details
The optimizer has numerous interesting technical features:
- React SPA without SSR with Vite
- Built with Material-UI 5 and Emotion for CSS-in-JS
- Statemanagement with ReduxJS
- multithreaded calculations with Rust compiled to WASM and WebWorkers
- i18n localization (Chinese and German)
- hosted on Cloudflare pages utilizing Workers and KV
- custom algorithm for lossless state compress based on a schema into base64, url-save strings

Binary file not shown.

After

Width:  |  Height:  |  Size: 568 KiB

View file

@ -1,3 +1,6 @@
User-agent: * User-agent: *
Disallow: /contact Disallow: /contact
Disallow: /admin Disallow: /admin
User-agent: GPTBot
Disallow: /

View file

@ -551,15 +551,10 @@ callsites@^3.0.0:
resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==
caniuse-lite@^1.0.30001400: caniuse-lite@^1.0.30001400, caniuse-lite@^1.0.30001426:
version "1.0.30001411" version "1.0.30001534"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001411.tgz#303c8594ca5903b193a6d875ac613548cb73379a" resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001534.tgz"
integrity sha512-HPnJKESKuhKpHvMY1/ux7J3nG7xG8jRuL4lbyCjDRm0doTNV91tcRk60xrP7Ym9DtJH/yuqntDWBJCqpXB4b7g== integrity sha512-vlPVrhsCS7XaSh2VvWluIQEzVhefrUQcEsQWSS5A5V+dM07uv1qHeQzAOTGIMy9i3e9bH15+muvI/UHojVgS/Q==
caniuse-lite@^1.0.30001426:
version "1.0.30001441"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001441.tgz#987437b266260b640a23cd18fbddb509d7f69f3e"
integrity sha512-OyxRR4Vof59I3yGWXws6i908EtGbMzVUi3ganaZQHmydk1iwDhRnvaPG2WaR0KcqrDFKrxVZHULT396LEPhXfg==
ccount@^2.0.0: ccount@^2.0.0:
version "2.0.1" version "2.0.1"